diff --git a/lib/main.dart b/lib/main.dart index 0a92840..2c95046 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,7 +2,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; - +import 'package:translator/translator.dart'; const kRowCount = 10; @@ -10,110 +10,235 @@ const kContentSize = 64.0; const kGutterWidth = 2.0; const kGutterInset = EdgeInsets.all(kGutterWidth); - +List languages = ['English', 'Türkçe', 'Deutsch', 'Español', 'Français','عربي', 'हिंदी']; +String selectedLanguage = 'English'; void main() { WidgetsFlutterBinding.ensureInitialized(); - final gridList = rootBundle.loadString('assets/elementsGrid.json') + final gridList = rootBundle + .loadString('assets/elementsGrid.json') .then((source) => jsonDecode(source)['elements'] as List) - .then((list) => list.map((json) => json != null ? ElementData.fromJson(json) : null).toList()); + .then((list) => list + .map((json) => json != null ? ElementData.fromJson(json) : null) + .toList()); runApp(ElementsApp(gridList)); } - class ElementData { - final String name, category, symbol, extract, source, atomicWeight; final int number; final List colors; ElementData.fromJson(Map json) - : name = json['name'], category = json['category'], symbol = json['symbol'], - extract = json['extract'], source = json['source'], - atomicWeight = json['atomic_weight'], number = json['number'], + : name = json['name'], + category = json['category'], + symbol = json['symbol'], + extract = json['extract'], + source = json['source'], + atomicWeight = json['atomic_weight'], + number = json['number'], colors = (json['colors'] as List).map((value) => Color(value)).toList(); } - class ElementsApp extends StatelessWidget { ElementsApp(this.gridList); - final Future> gridList; + final Future> gridList; @override Widget build(BuildContext context) { final theme = ThemeData( brightness: Brightness.dark, accentColor: Colors.grey, - - textTheme: Typography.whiteMountainView.apply(fontFamily: 'Roboto Condensed'), - primaryTextTheme: Typography.whiteMountainView.apply(fontFamily: 'Share Tech Mono'), + textTheme: + Typography.whiteMountainView.apply(fontFamily: 'Roboto Condensed'), + primaryTextTheme: + Typography.whiteMountainView.apply(fontFamily: 'Share Tech Mono'), ); - return MaterialApp(title: 'Elements', theme: theme, home: TablePage(gridList)); + return MaterialApp( + title: 'Elements', + theme: theme, + home: TablePage(gridList), + debugShowCheckedModeBanner: false, + ); } } -class TablePage extends StatelessWidget { +class TablePage extends StatefulWidget { TablePage(this.gridList); - final Future> gridList; + final Future> gridList; + + @override + State createState() => _TablePageState(); +} + +class _TablePageState extends State { + + void selectLanguage(String language) { + setState(() { + selectedLanguage = language; + }); + } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.blueGrey[900], - appBar: AppBar(title: Text('Elements'), centerTitle: true, backgroundColor: Colors.blueGrey[800]), + appBar: AppBar( + title: Text( + 'Elements', + style: TextStyle(fontFamily: "Share Tech Mono"), + ), + centerTitle: true, + backgroundColor: Colors.blueGrey[800], + actions: [ + PopupMenuButton( + icon: Icon(Icons.language), + itemBuilder: (BuildContext context) { + return languages.map((String language) { + return PopupMenuItem( + value: language, + child: Text(language), + ); + }).toList(); + }, + onSelected: selectLanguage, + ), + ], + ), body: FutureBuilder( - future: gridList, - builder: (_, snapshot) => snapshot.hasData ? _buildTable(snapshot.data) + future: widget.gridList, + builder: (_, snapshot) => snapshot.hasData + ? _buildTable(snapshot.data) : Center(child: CircularProgressIndicator()), ), ); } - Widget _buildTable(List elements) { - final tiles = elements.map((element) => element != null ? ElementTile(element) - : Container(color: Colors.black38, margin: kGutterInset)).toList(); + Widget _buildTable(List? elements) { + final tiles = elements! + .map((element) => element != null + ? ElementTile(element) + : Container(color: Colors.black38, margin: kGutterInset)) + .toList(); return SingleChildScrollView( - child: SizedBox(height: kRowCount * (kContentSize + (kGutterWidth * 2)), - child: GridView.count(crossAxisCount: kRowCount, children: tiles, - scrollDirection: Axis.horizontal,),),); + child: SizedBox( + height: kRowCount * (kContentSize + (kGutterWidth * 2)), + child: GridView.count( + crossAxisCount: kRowCount, + children: tiles, + scrollDirection: Axis.horizontal, + ), + ), + ); } } -class DetailPage extends StatelessWidget { +class DetailPage extends StatefulWidget { DetailPage(this.element); final ElementData element; + @override + State createState() => _DetailPageState(); +} + +class _DetailPageState extends State { + GoogleTranslator translator = GoogleTranslator(); + var atomic = 'Atomic Weight'; + @override Widget build(BuildContext context) { - final listItems = [ - ListTile(leading: Icon(Icons.category), title : Text(element.category.toUpperCase())), - ListTile(leading: Icon(Icons.info), title : Text(element.extract), - subtitle: Text(element.source),), - ListTile(leading: Icon(Icons.fiber_smart_record), title: Text(element.atomicWeight), - subtitle: Text('Atomic Weight'),), + var theExtract = widget.element.extract; + var theCategory = widget.element.category.toUpperCase(); + + var listItems = [ + ListTile(leading: Icon(Icons.category), title: Text(theCategory)), + ListTile( + leading: Icon(Icons.info), + title: Text(theExtract), + subtitle: Text(widget.element.source), + ), + ListTile( + leading: Icon(Icons.fiber_smart_record), + title: Text(widget.element.atomicWeight), + subtitle: Text(atomic), + ), ].expand((widget) => [widget, Divider()]).toList(); - return Scaffold( - backgroundColor: Color.lerp(Colors.grey[850], element.colors[0], 0.07), + Future> translateAll(String language) async { + var theExtract = widget.element.extract; + var theCategory = widget.element.category.toUpperCase(); + var atomic = 'Atomic Weight'; + + var results = await Future.wait([ + translator + .translate(theExtract, to: language) + .then((value) => value.toString()), + translator + .translate(theCategory, to: language) + .then((value) => value.toString()), + translator + .translate(atomic, to: language) + .then((value) => value.toString()), + ]); + + return results; + } + return Scaffold( + backgroundColor: + Color.lerp(Colors.grey[850], widget.element.colors[0], 0.07), appBar: AppBar( - backgroundColor: Color.lerp(Colors.grey[850], element.colors[1], 0.2), - bottom: ElementTile(element, isLarge: true),), - - body: ListView(padding: EdgeInsets.only(top: 24.0), children: listItems), + backgroundColor: + Color.lerp(Colors.grey[850], widget.element.colors[1], 0.2), + bottom: ElementTile(widget.element, isLarge: true),), + body: FutureBuilder>( + future: translateAll(selectedLanguage == "English" ? "en": selectedLanguage == "Türkçe" ? "tr": selectedLanguage == "Deutsch" ? "de": selectedLanguage == "عربي" ? "ar": selectedLanguage == "हिंदी" ? "hi": selectedLanguage == "Español" ? "es": selectedLanguage=="Français" ? "fr": "en"), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return Center( + child: CircularProgressIndicator( + color: Colors.orangeAccent, + )); + } else if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + var translatedExtract = snapshot.data![0]; + var translatedCategory = snapshot.data![1]; + var translatedAtomic = snapshot.data![2]; + + var listItems = [ + ListTile( + leading: Icon(Icons.category), + title: Text(translatedCategory)), + ListTile( + leading: Icon(Icons.info), + title: Text(translatedExtract), + subtitle: Text(widget.element.source), + ), + ListTile( + leading: Icon(Icons.fiber_smart_record), + title: Text(widget.element.atomicWeight), + subtitle: Text(translatedAtomic), + ), + ].expand((widget) => [widget, Divider()]).toList(); + + return ListView( + padding: EdgeInsets.only(top: 24.0), children: listItems); + } + }, + ), ); } } - class ElementTile extends StatelessWidget implements PreferredSizeWidget { - const ElementTile(this.element, { this.isLarge = false }); + const ElementTile(this.element, {this.isLarge = false}); final ElementData element; final bool isLarge; @@ -123,11 +248,18 @@ class ElementTile extends StatelessWidget implements PreferredSizeWidget { @override Widget build(BuildContext context) { final tileText = [ - Align(alignment: AlignmentDirectional.centerStart, - child: Text('${element.number}', style: TextStyle(fontSize: 10.0)),), - Text(element.symbol, style: Theme.of(context).primaryTextTheme.headline), - Text(element.name, maxLines: 1, overflow: TextOverflow.ellipsis, - textScaleFactor: isLarge ? 0.65 : 1,), + Align( + alignment: AlignmentDirectional.centerStart, + child: Text('${element.number}', style: TextStyle(fontSize: 10.0)), + ), + Text(element.symbol, + style: Theme.of(context).primaryTextTheme.headlineSmall), + Text( + element.name, + maxLines: 1, + overflow: TextOverflow.ellipsis, + textScaleFactor: isLarge ? 0.65 : 1, + ), ]; final tile = Container( @@ -136,21 +268,26 @@ class ElementTile extends StatelessWidget implements PreferredSizeWidget { height: kContentSize, foregroundDecoration: BoxDecoration( gradient: LinearGradient(colors: element.colors), - backgroundBlendMode: BlendMode.multiply,), + backgroundBlendMode: BlendMode.multiply, + ), child: RawMaterialButton( - onPressed: !isLarge ? () => Navigator.push(context, - MaterialPageRoute(builder: (_) => DetailPage(element))) : null, + onPressed: !isLarge + ? () => Navigator.push( + context, MaterialPageRoute(builder: (_) => DetailPage(element))) + : null, fillColor: Colors.grey[800], disabledElevation: 10.0, padding: kGutterInset * 2.0, - child: Column(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: tileText), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: tileText), ), ); return Hero( tag: 'hero-${element.symbol}', - flightShuttleBuilder: (_, anim, __, ___, ____) => - ScaleTransition(scale: anim.drive(Tween(begin: 1, end: 1.75)), child: tile), + flightShuttleBuilder: (_, anim, __, ___, ____) => ScaleTransition( + scale: anim.drive(Tween(begin: 1, end: 1.75)), child: tile), child: Transform.scale(scale: isLarge ? 1.75 : 1, child: tile), ); } diff --git a/pubspec.yaml b/pubspec.yaml index c954bf1..cf9f7d6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,7 +12,8 @@ dependencies: sdk: flutter cupertino_icons: ^0.1.2 - http: ^0.12.0+1 + http: ^0.13.5 + translator: ^0.1.7 dev_dependencies: flutter_test: @@ -45,4 +46,4 @@ flutter_icons: image_path_android: "assets/launcher_icons/launcher_android.png" image_path_ios: "assets/launcher_icons/launcher_ios.png" adaptive_icon_foreground: "assets/launcher_icons/launcher_adaptive_foreground.png" - adaptive_icon_background: "assets/launcher_icons/launcher_adaptive_background.png" \ No newline at end of file + adaptive_icon_background: "assets/launcher_icons/launcher_adaptive_background.png"