diff --git a/assets/info.svg b/assets/info.svg new file mode 100644 index 0000000..bd97063 --- /dev/null +++ b/assets/info.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/radio_button_unchecked.svg b/assets/radio_button_unchecked.svg new file mode 100644 index 0000000..45af45a --- /dev/null +++ b/assets/radio_button_unchecked.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/task_alt.svg b/assets/task_alt.svg new file mode 100644 index 0000000..75cbab4 --- /dev/null +++ b/assets/task_alt.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart index 772f7bf..6d719a8 100644 --- a/lib/i18n/strings.g.dart +++ b/lib/i18n/strings.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 1 -/// Strings: 9 +/// Strings: 19 /// -/// Built on 2024-08-02 at 06:45 UTC +/// Built on 2024-08-08 at 12:09 UTC // coverage:ignore-file // ignore_for_file: type=lint @@ -148,6 +148,7 @@ class Translations implements BaseTranslations { // Translations late final _StringsMenuEn menu = _StringsMenuEn._(_root); + late final _StringsCompanyScreenEn companyScreen = _StringsCompanyScreenEn._(_root); } // Path: menu @@ -168,6 +169,25 @@ class _StringsMenuEn { String get footer => 'Aplikacja Pola \n© Klub Jagielloński'; } +// Path: companyScreen +class _StringsCompanyScreenEn { + _StringsCompanyScreenEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get ourRating => 'Nasza ocena:'; + String get gradingCriteria => 'Kryteria oceniania:'; + String get polishCapital => 'Polski kapitał'; + String get producedInPoland => 'Produkuje w Polsce'; + String get researchInPoland => 'Prowadzi badania w Polsce'; + String get registeredInPoland => 'Zarejestrowana w Polsce'; + String get notConcernPart => 'Nie jest częścią zagranicznego koncernu'; + String get seeMore => ' zobacz więcej'; + String get seeLess => ' zobacz mniej'; + String points({required Object score}) => '${score} pkt'; +} + /// Flat map(s) containing all translations. /// Only for edge cases! For simple maps, use the map function of this library. @@ -183,6 +203,16 @@ extension on Translations { case 'menu.team': return 'Zespół'; case 'menu.findUs': return 'Znajdź nas tutaj'; case 'menu.footer': return 'Aplikacja Pola \n© Klub Jagielloński'; + case 'companyScreen.ourRating': return 'Nasza ocena:'; + case 'companyScreen.gradingCriteria': return 'Kryteria oceniania:'; + case 'companyScreen.polishCapital': return 'Polski kapitał'; + case 'companyScreen.producedInPoland': return 'Produkuje w Polsce'; + case 'companyScreen.researchInPoland': return 'Prowadzi badania w Polsce'; + case 'companyScreen.registeredInPoland': return 'Zarejestrowana w Polsce'; + case 'companyScreen.notConcernPart': return 'Nie jest częścią zagranicznego koncernu'; + case 'companyScreen.seeMore': return ' zobacz więcej'; + case 'companyScreen.seeLess': return ' zobacz mniej'; + case 'companyScreen.points': return ({required Object score}) => '${score} pkt'; default: return null; } } diff --git a/lib/i18n/strings.i18n.json b/lib/i18n/strings.i18n.json index eb728b8..c3670ba 100644 --- a/lib/i18n/strings.i18n.json +++ b/lib/i18n/strings.i18n.json @@ -9,5 +9,17 @@ "team": "Zespół", "findUs": "Znajdź nas tutaj", "footer": "Aplikacja Pola \n© Klub Jagielloński" + }, + "companyScreen": { + "ourRating": "Nasza ocena:", + "gradingCriteria": "Kryteria oceniania:", + "polishCapital": "Polski kapitał", + "producedInPoland": "Produkuje w Polsce", + "researchInPoland": "Prowadzi badania w Polsce", + "registeredInPoland": "Zarejestrowana w Polsce", + "notConcernPart":"Nie jest częścią zagranicznego koncernu", + "seeMore":" zobacz więcej", + "seeLess":" zobacz mniej", + "points":"$score pkt" } } diff --git a/lib/pages/detail/detail.dart b/lib/pages/detail/detail.dart index c113ea9..0dc7bbe 100644 --- a/lib/pages/detail/detail.dart +++ b/lib/pages/detail/detail.dart @@ -1,11 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:pola_flutter/analytics/pola_analytics.dart'; -import 'package:pola_flutter/models/brand.dart'; import 'package:pola_flutter/models/search_result.dart'; -import 'package:pola_flutter/ui/progress_indicator_text.dart'; -import 'package:url_launcher/url_launcher.dart'; - import 'detail_lidl.dart'; +import 'detail_content.dart'; class DetailPage extends StatelessWidget { DetailPage({Key? key, required this.searchResult}) : super(key: key); @@ -18,32 +14,22 @@ class DetailPage extends StatelessWidget { return LidlDetailPage(searchResult: searchResult); } - final company = searchResult.companies?.first; return Scaffold( backgroundColor: Colors.white, + appBar: AppBar( title: Text(searchResult.name ?? ""), - leading: new IconButton( - icon: new Icon(Icons.arrow_back), + leading: IconButton( + icon: Icon(Icons.arrow_back), onPressed: () => Navigator.of(context).pop(), ), ), body: SafeArea( - child: SingleChildScrollView( + child: SingleChildScrollView( child: Column( children: [ - Padding( - padding: EdgeInsets.all(12.0), - child: Align( - child: Text(searchResult.name ?? "", - style: TextStyle( - fontSize: 18.0, - )), - alignment: Alignment.centerLeft, - )), - LinearProgressIndicatorWithText((company?.plScore ?? 0).toDouble(), - (((company?.plScore ?? "0").toString()) + " pkt")), - _DetailContent(searchResult) + SizedBox(height: 16.0), + DetailContent(searchResult), ], ), ), @@ -51,165 +37,3 @@ class DetailPage extends StatelessWidget { ); } } - -class _DetailContent extends StatelessWidget { - _DetailContent(this.searchResult); - - final SearchResult searchResult; - - @override - Widget build(BuildContext context) { - if (searchResult.companies == null) { - return Padding( - padding: EdgeInsets.all(8.0), - child: Text(searchResult.altText ?? "")); - } - final company = searchResult.companies!.first; - return Column( - children: [ - Padding( - padding: EdgeInsets.all(8.0), - child: Column( - children: [ - Padding( - padding: EdgeInsets.all(4.0), - child: Align( - child: Text("udział polskiego kapitału"), - alignment: Alignment.centerLeft, - )), - LinearProgressIndicatorWithText( - (company.plCapital ?? 0).toDouble(), - (company.plCapital ?? 0).toString() + "%"), - ], - ), - ), - _DetailItem("produkuje w Polsce", (company.plWorkers ?? 0) != 0), - _DetailItem("prowadzi badania w Polsce", (company.plRnD ?? 0) != 0), - _DetailItem("zarejestrowana w Polsce", (company.plRegistered ?? 0) != 0), - _DetailItem("nie jest częścią zagranicznego koncernu", - (company.plNotGlobEnt ?? 0) != 0), - Padding( - padding: EdgeInsets.all(8.0), - child: Text(company.description ?? "")), - _DetailCompanyLogotype(company.logotypeUrl), - _BrandLogotypes(searchResult.allCompanyBrands), - _ReadMoreButton(searchResult) - ], - ); - } -} - -class _DetailItem extends StatelessWidget { - _DetailItem(this.text, this.state); - - final String text; - final bool state; - - @override - Widget build(BuildContext context) { - return Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.all(4.0), - child: SizedBox( - height: 32.0, - width: 32.0, - child: Container( - child: Checkbox( - checkColor: Colors.white, - value: state, - onChanged: (bool? value) {}, - ), - ), - ), - ), - Text(text) - ], - ); - } -} - -class _ReadMoreButton extends StatelessWidget { - _ReadMoreButton(this.searchResult); - - final SearchResult searchResult; - final PolaAnalytics _analytics = PolaAnalytics.instance(); - - @override - Widget build(BuildContext context) { - final stringUrl = searchResult.companies?.first.officialUrl; - if (stringUrl == null) { - return Container(); - } - Uri? url = Uri.tryParse(stringUrl); - if (url == null) { - return Container(); - } - - return ElevatedButton( - onPressed: () { - _analytics.readMore(searchResult, stringUrl); - launchUrl( - url, - mode: LaunchMode.externalApplication, - ); - }, - child: Text("Czytaj więcej!"), - ); - } -} - -class _DetailCompanyLogotype extends StatelessWidget { - _DetailCompanyLogotype(this.url); - - final String? url; - - @override - Widget build(BuildContext context) { - final url = this.url; - if (url == null) { - return Container(); - } - - return _LogoView(url); - } -} - -class _BrandLogotypes extends StatelessWidget { - _BrandLogotypes(this.brands); - - final List? brands; - - @override - Widget build(BuildContext context) { - final logotypes = brands?.map((brand) => brand.logotypeUrl).where((url) => url != null).toList().cast(); - if (logotypes == null) { - return Container(); - } - - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: logotypes - .map((logotypeUrl) => Padding( - padding: EdgeInsets.all(8.0), - child: _LogoView(logotypeUrl))) - .toList(), - ), - ); - } -} - -class _LogoView extends StatelessWidget { - _LogoView(this.url); - - final String url; - - @override - Widget build(BuildContext context) { - return Image.network(url, height: 100.0, fit: BoxFit.contain); - } -} diff --git a/lib/pages/detail/detail_content.dart b/lib/pages/detail/detail_content.dart new file mode 100644 index 0000000..2ef323e --- /dev/null +++ b/lib/pages/detail/detail_content.dart @@ -0,0 +1,235 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:pola_flutter/models/company.dart'; +import 'package:pola_flutter/models/search_result.dart'; +import 'package:pola_flutter/i18n/strings.g.dart'; +import 'logotypes.dart'; +import 'expandandable_text.dart'; +import 'polish_capital_graph.dart'; + +class DetailContent extends StatelessWidget { + DetailContent(this.searchResult); + + final SearchResult searchResult; + + @override + Widget build(BuildContext context) { + if (searchResult.companies == null) { + return Padding( + padding: EdgeInsets.all(8.0), + child: Text(searchResult.altText ?? ""), + ); + } + + final company = searchResult.companies!.first; + final score = company.plScore ?? 0; + final double plCapital = (company.plCapital ?? 0).toDouble(); + final Translations t = Translations.of(context); + + final hasLogo = company.logotypeUrl != null; + final hasDescription = company.description?.isNotEmpty ?? false; + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 17.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Align( + alignment: Alignment.centerLeft, + child: Row( + children: [ + SvgPicture.asset( + 'assets/info.svg', + height: 24.0, + width: 24.0, + ), + SizedBox(width: 8.0), + Text( + t.companyScreen.ourRating, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w600, + fontFamily: 'Lato', + color: Color(0xFF1C1B1F), + ), + ), + SizedBox(width: 8.0), + Text( + t.companyScreen.points(score: score), + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.w700, + fontFamily: 'Lato', + color: Color(0xFF1C1B1F), + ), + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(10.0), + child: LinearProgressIndicator( + value: score / 100.0, + backgroundColor: Color(0xFFF5DEDD), + valueColor: AlwaysStoppedAnimation(Color(0xFFE1203E)), + minHeight: 12.0, + ), + ), + ), + SizedBox(height: 17.0), + Divider( + thickness: 1.0, + color: Color(0xFFF0F0F0), + indent: 0, + endIndent: 0, + ), + Padding( + padding: const EdgeInsets.only(top: 22.0), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + t.companyScreen.gradingCriteria, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w600, + fontFamily: 'Lato', + color: Color(0xFF1C1B1F), + ), + ), + ), + ), + SizedBox(height: 22.0), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + PolishCapitalGraph(percentage: plCapital), + SizedBox(width: 35.0), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _DetailItem(t.companyScreen.producedInPoland, + (company.plWorkers ?? 0) != 0), + SizedBox(height: 14.0), + _DetailItem(t.companyScreen.researchInPoland, + (company.plRnD ?? 0) != 0), + SizedBox(height: 14.0), + _DetailItem(t.companyScreen.registeredInPoland, + (company.plRegistered ?? 0) != 0), + SizedBox(height: 14.0), + _DetailItem(t.companyScreen.notConcernPart, + (company.plNotGlobEnt ?? 0) != 0), + ], + ), + ), + ], + ), + SizedBox(height: 22.0), + Divider( + thickness: 1.0, + color: Color(0xFFF0F0F0), + indent: 0, + endIndent: 0, + ), + if (hasDescription) ...[ + Padding( + padding: EdgeInsets.symmetric(vertical: 22.0), + child: ExpandableText(company.description ?? ""), + ), + if (hasLogo) + Divider( + thickness: 1.0, + color: Color(0xFFF0F0F0), + indent: 0, + endIndent: 0, + ), + ], + if (hasLogo) + Logotypes( + logotypes: searchResult.logotypes(), + searchResult: searchResult), + SizedBox(height: 26.0), + if (hasLogo) + Divider( + thickness: 1.0, + color: Color(0xFFF0F0F0), + indent: 0, + endIndent: 0, + ), + ], + ), + ); + } +} + +class _DetailItem extends StatelessWidget { + _DetailItem(this.text, this.state); + + final String text; + final bool state; + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(right: 3.0), + child: SvgPicture.asset( + state ? 'assets/task_alt.svg' : 'assets/radio_button_unchecked.svg', + ), + ), + Expanded( + child: Text( + text, + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w400, + fontFamily: 'Lato', + color: Color(0xFF1C1B1F), + ), + softWrap: true, + overflow: TextOverflow.visible, + ), + ), + ], + ); + } +} + +extension on SearchResult { + List logotypes() { + var brandLogotypes = allCompanyBrands?.map((brand) { + final brandLogotype = brand.logotypeUrl; + if (brandLogotype != null) { + return Logotype(brandLogotype, null); + } else { + return null; + } + }).toList() ?? + []; + + final logotypeCompany = companies?.first.logotype(); + + brandLogotypes.insert(0, logotypeCompany); + + return brandLogotypes + .where((logotype) => logotype != null) + .cast() + .toList(); + } +} + +extension on Company { + Logotype? logotype() { + final logotypeUrl = this.logotypeUrl; + if (logotypeUrl != null) { + return Logotype(logotypeUrl, officialUrl); + } else { + return null; + } + } +} diff --git a/lib/pages/detail/expandandable_text.dart b/lib/pages/detail/expandandable_text.dart new file mode 100644 index 0000000..cdf74ee --- /dev/null +++ b/lib/pages/detail/expandandable_text.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/gestures.dart'; +import 'package:pola_flutter/i18n/strings.g.dart'; + +class ExpandableText extends StatefulWidget { + final String text; + ExpandableText(this.text); + + @override + _ExpandableTextState createState() => _ExpandableTextState(); +} + +class _ExpandableTextState extends State { + bool isExpanded = false; + + @override + Widget build(BuildContext context) { + final link = TextSpan( + style: TextStyle( + color: Color(0xFF898989), + fontSize: 11.0, + fontWeight: FontWeight.w700, + fontFamily: 'Lato', + ), + text: isExpanded ? t.companyScreen.seeLess : t.companyScreen.seeMore, + recognizer: TapGestureRecognizer() + ..onTap = () { + setState(() { + isExpanded = !isExpanded; + }); + }, + ); + + return LayoutBuilder( + builder: (context, constraints) { + final textSpan = TextSpan( + text: widget.text, + style: TextStyle( + color: Color(0xFF1C1B1F), + fontSize: 11.0, + fontWeight: FontWeight.w400, + fontFamily: 'Lato', + ), + ); + + final textPainter = TextPainter( + text: textSpan, + maxLines: isExpanded ? null : 3, + ellipsis: '...', + textDirection: TextDirection.ltr, + ); + + textPainter.layout( + minWidth: constraints.minWidth, + maxWidth: constraints.maxWidth, + ); + + final linkTextPainter = TextPainter( + text: link, + textDirection: TextDirection.ltr, + ); + + linkTextPainter.layout( + minWidth: constraints.minWidth, + maxWidth: constraints.maxWidth, + ); + + if (!isExpanded && textPainter.didExceedMaxLines) { + final pos = textPainter.getPositionForOffset(Offset( + textPainter.width - linkTextPainter.width, + textPainter.height, + )); + final end = textPainter.getOffsetBefore(pos.offset); + final text = TextSpan( + text: widget.text.substring(0, end), + style: TextStyle(color: Color(0xFF1C1B1F)), + children: [link], + ); + + return RichText( + text: text, + ); + } else { + return RichText( + text: TextSpan( + text: widget.text, + style: TextStyle(color: Color(0xFF1C1B1F)), + children: [if (isExpanded) link], + ), + ); + } + }, + ); + } +} diff --git a/lib/pages/detail/logotypes.dart b/lib/pages/detail/logotypes.dart new file mode 100644 index 0000000..d25521f --- /dev/null +++ b/lib/pages/detail/logotypes.dart @@ -0,0 +1,79 @@ +import 'package:flutter/material.dart'; +import 'package:pola_flutter/analytics/pola_analytics.dart'; +import 'package:pola_flutter/models/search_result.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class Logotype { + final String imageUrl; + final String? websiteUrl; + + Logotype(this.imageUrl, this.websiteUrl); +} + +class Logotypes extends StatelessWidget { + final List logotypes; + final SearchResult searchResult; + final PolaAnalytics analytics = PolaAnalytics.instance(); + + Logotypes({required this.logotypes, required this.searchResult}); + + @override + Widget build(BuildContext context) { + if (logotypes.isEmpty) { + return Container(); + } + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: logotypes.map((logotype) { + return GestureDetector( + onTap: () { + final url = logotype.websiteUrl; + if (url == null) return; + final Uri? uri = Uri.tryParse(url); + if (uri == null) return; + + analytics.readMore(searchResult, url); + launchUrl( + uri, + mode: LaunchMode.externalApplication, + ); + }, + child: Padding( + padding: EdgeInsets.all(8.0), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), + color: Color(0xFFF8F8F8), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.3), + spreadRadius: 1, + blurRadius: 5, + offset: Offset(0, 3), + ), + ], + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: _LogoView(logotype.imageUrl), + ), + ), + ), + ); + }).toList(), + ), + ); + } +} + +class _LogoView extends StatelessWidget { + _LogoView(this.url); + + final String url; + + @override + Widget build(BuildContext context) { + return Image.network(url, height: 60.0, fit: BoxFit.contain); + } +} diff --git a/lib/pages/detail/polish_capital_graph.dart b/lib/pages/detail/polish_capital_graph.dart new file mode 100644 index 0000000..0fcfb35 --- /dev/null +++ b/lib/pages/detail/polish_capital_graph.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_gauges/gauges.dart'; +import 'package:pola_flutter/i18n/strings.g.dart'; + +class PolishCapitalGraph extends StatelessWidget { + final double percentage; + + PolishCapitalGraph({required this.percentage}); + + @override + Widget build(BuildContext context) { + final size = 140.0; + final thickness = 0.15; + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + height: size, + width: size, + child: SfRadialGauge( + axes: [ + RadialAxis( + minimum: 0, + maximum: 100, + showLabels: false, + showTicks: false, + axisLineStyle: AxisLineStyle( + thickness: thickness, + cornerStyle: CornerStyle.bothCurve, + color: Color(0xFFF5DEDD), + thicknessUnit: GaugeSizeUnit.factor, + ), + pointers: [ + RangePointer( + value: percentage, + cornerStyle: CornerStyle.bothCurve, + width: thickness, + sizeUnit: GaugeSizeUnit.factor, + color: Color(0xFFE1203E), + ), + ], + annotations: [ + GaugeAnnotation( + positionFactor: 0.01, + angle: 90, + widget: Text( + '${percentage.toInt()}%', + style: TextStyle( + fontSize: 26.0, + fontWeight: FontWeight.w700, + fontFamily: 'Lato', + color: Color(0xFF1C1B1F), + ), + ), + ), + ], + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.only(top: 0.0), + child: Text( + t.companyScreen.polishCapital, + style: TextStyle( + fontSize: 11.0, + fontWeight: FontWeight.w400, + color: Color(0xFF1C1B1F), + fontFamily: 'Lato', + ), + ), + ), + ], + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index a077310..9b50a02 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -430,6 +430,14 @@ packages: url: "https://pub.dev" source: hosted version: "8.1.6" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" + url: "https://pub.dev" + source: hosted + version: "2.0.10+1" flutter_test: dependency: "direct dev" description: flutter @@ -504,6 +512,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.5" + intl: + dependency: transitive + description: + name: intl + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + url: "https://pub.dev" + source: hosted + version: "0.19.0" io: dependency: transitive description: @@ -672,6 +688,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.0" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" path_provider_linux: dependency: transitive description: @@ -696,6 +720,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" platform: dependency: transitive description: @@ -957,6 +989,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + syncfusion_flutter_core: + dependency: transitive + description: + name: syncfusion_flutter_core + sha256: fd4d2cdbf8d0d1e3441817cb8a03f896566fad5187788957e78492fe16800388 + url: "https://pub.dev" + source: hosted + version: "26.2.7" + syncfusion_flutter_gauges: + dependency: "direct main" + description: + name: syncfusion_flutter_gauges + sha256: "009f85edcb59dac20f1c5b445170de74eb65be774c6fdd4f8dc7bbc00e261f32" + url: "https://pub.dev" + source: hosted + version: "26.2.7" term_glyph: dependency: transitive description: @@ -1077,6 +1125,30 @@ packages: url: "https://pub.dev" source: hosted version: "4.4.0" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" vector_math: dependency: transitive description: @@ -1213,6 +1285,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 1226f87..1bc7f94 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,6 +32,8 @@ dependencies: firebase_analytics: ^11.1.0 slang: ^3.31.1 slang_flutter: ^3.31.0 + syncfusion_flutter_gauges: ^26.1.42 + flutter_svg: ^2.0.9 dev_dependencies: flutter_test: