diff --git a/analysis_options.yaml b/analysis_options.yaml index 839cc64..6c1ade2 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -24,6 +24,9 @@ linter: rules: # avoid_print: false # Uncomment to disable the `avoid_print` rule # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + prefer_const_literals_to_create_immutables: false + prefer_const_constructors: false + avoid_print: false # Additional information about this file can be found at # https://dart.dev/guides/language/analysis-options \ No newline at end of file diff --git a/lib/app.dart b/lib/app.dart index e04eb3e..f86272a 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -7,21 +7,20 @@ class App extends StatelessWidget { Widget build(BuildContext context) { final AppState state = AppState(); - return AppStateProvider( - state: state, - child: MaterialApp( - title: 'Neumorphism', - debugShowCheckedModeBanner: false, - theme: ThemeData( - // primarySwatch: Colors.amber, - textTheme: GoogleFonts.latoTextTheme(), - ), - // locale: AppLocalizations.supportedLocales.last, - localizationsDelegates: AppLocalizations.localizationsDelegates, - supportedLocales: AppLocalizations.supportedLocales, - home: const HomePage(), - routes: appRoutes, + return MaterialApp( + title: 'Neumorphism', + debugShowCheckedModeBanner: false, + theme: ThemeData( + textTheme: GoogleFonts.latoTextTheme(), ), + // locale: AppLocalizations.supportedLocales.last, + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: AppStateProvider( + state: state, + child: const HomePage(), + ), + routes: appRoutes, ); } } diff --git a/lib/exports.dart b/lib/exports.dart index 924a5fb..2884b0e 100644 --- a/lib/exports.dart +++ b/lib/exports.dart @@ -1,5 +1,7 @@ import 'dart:ui'; export 'dart:math'; +export 'dart:typed_data'; +export 'dart:convert'; export 'package:flutter/material.dart'; export 'package:flutter/services.dart'; diff --git a/lib/home/home_page.dart b/lib/home/home_page.dart index 83efadf..35da59e 100644 --- a/lib/home/home_page.dart +++ b/lib/home/home_page.dart @@ -45,37 +45,18 @@ class _HomePageState extends State { } } - void _downloadImage() async { - try { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(AppLocalizations.of(context)!.download), - action: SnackBarAction( - label: 'OK', - textColor: Colors.amber, - onPressed: () { - ScaffoldMessenger.of(context).hideCurrentSnackBar(); - }, - ), - ), - ); - } catch (e) { - debugPrint(e.toString()); - } - } - @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( actions: [ IconButton( - onPressed: _copyCode, + onPressed: provider.downloadImage, icon: const Icon(Icons.download, color: Colors.white), ), const SizedBox(width: 10.0), IconButton( - onPressed: _downloadImage, + onPressed: _copyCode, icon: const Icon(Icons.copy, color: Colors.white), ), const SizedBox(width: 10.0), @@ -110,7 +91,7 @@ class _HomePageState extends State { child: Column( mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.center, - children: const [ + children: [ PreviewBox(), SizedBox(height: 20.0), StylesController(), diff --git a/lib/home/widgets/preview_box.dart b/lib/home/widgets/preview_box.dart index 517148e..c601c16 100644 --- a/lib/home/widgets/preview_box.dart +++ b/lib/home/widgets/preview_box.dart @@ -7,6 +7,7 @@ class PreviewBox extends StatelessWidget { Widget build(BuildContext context) { late final AppStateProviderState provider = AppStateProvider.of(context); late final AppState state = provider.state; + final int depth = state.intensity.toInt(); final Color darkColor = getAdjustColor(state.color, depth); final Color lightColor = getAdjustColor(state.color, -depth); @@ -64,36 +65,42 @@ class PreviewBox extends StatelessWidget { ), ]; + Widget previewBox = Container( + height: 400.0, + alignment: Alignment.center, + color: state.color, + child: Container( + width: state.size, + height: state.size, + child: Icon( + Icons.favorite, + size: iconSize, + color: Colors.amber, + ), + transformAlignment: Alignment.center, + decoration: BoxDecoration( + color: state.color, + borderRadius: BorderRadius.circular(state.radius), + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: gradientColors, + ), + boxShadow: shadowList, + ), + ), + ); + + provider.changePreview( + SizedBox(width: 400.0, height: 400.0, child: previewBox), + ); + return LayoutBuilder(builder: (context, BoxConstraints constraints) { final double pos = constraints.maxWidth / 4; return Stack( children: [ - Container( - height: 400.0, - alignment: Alignment.center, - color: state.color, - child: Container( - width: state.size, - height: state.size, - child: Icon( - Icons.favorite, - size: iconSize, - color: Colors.amber, - ), - transformAlignment: Alignment.center, - decoration: BoxDecoration( - color: state.color, - borderRadius: BorderRadius.circular(state.radius), - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: gradientColors, - ), - boxShadow: shadowList, - ), - ), - ), + previewBox, Positioned( top: 25.0, left: pos, diff --git a/lib/state/app_state.dart b/lib/state/app_state.dart index dc86ea3..6efc920 100644 --- a/lib/state/app_state.dart +++ b/lib/state/app_state.dart @@ -14,6 +14,7 @@ class AppState { Direction direction; CurveType type; String code; + Widget preview; AppState({ this.color = const Color(0xff333333), @@ -25,5 +26,6 @@ class AppState { this.direction = Direction.topLeft, this.type = CurveType.flat, this.code = '', + this.preview = const SizedBox.shrink(), }); } diff --git a/lib/state/app_state_provider.dart b/lib/state/app_state_provider.dart index c893104..dde4eb5 100644 --- a/lib/state/app_state_provider.dart +++ b/lib/state/app_state_provider.dart @@ -1,4 +1,5 @@ import '../exports.dart'; +import 'package:universal_html/html.dart' as html; class AppStateProvider extends StatefulWidget { final Widget child; @@ -22,6 +23,7 @@ class AppStateProvider extends StatefulWidget { class AppStateProviderState extends State { late AppState state; + final ScreenshotController screenshotController = ScreenshotController(); changeRadius(double val) { state.radius = val; @@ -75,6 +77,10 @@ class AppStateProviderState extends State { setState(() {}); } + changePreview(Widget widget) { + state.preview = widget; + } + setCode() { final int depth = state.intensity.toInt(); final Color darkColor = getAdjustColor(state.color, depth); @@ -168,6 +174,47 @@ class AppStateProviderState extends State { setState(() {}); } + void _capturedImage(Uint8List image) async { + final base64data = base64Encode(image); + final a = html.AnchorElement(href: 'data:image/jpeg;base64,$base64data'); + a.download = 'Neumorphism.jpg'; + a.click(); + a.remove(); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(AppLocalizations.of(context)!.download), + action: SnackBarAction( + label: 'OK', + textColor: Colors.amber, + onPressed: () { + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + }, + ), + ), + ); + } + + void _catchError(onError) { + print(onError); + } + + void downloadImage() async { + try { + final double pixelRatio = MediaQuery.of(context).devicePixelRatio; + + screenshotController + .captureFromWidget( + state.preview, + pixelRatio: pixelRatio, + ) + .then(_capturedImage) + .catchError(_catchError); + } catch (e) { + debugPrint(e.toString()); + } + } + @override void initState() { state = widget.state; diff --git a/pubspec.lock b/pubspec.lock index 222f594..5a3868f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -57,6 +57,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1" + csslib: + dependency: transitive + description: + name: csslib + url: "https://pub.dartlang.org" + source: hosted + version: "0.17.0" fake_async: dependency: transitive description: @@ -133,6 +140,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.7.0" + html: + dependency: transitive + description: + name: html + url: "https://pub.dartlang.org" + source: hosted + version: "0.15.0" http: dependency: transitive description: @@ -341,6 +355,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0" + universal_html: + dependency: "direct main" + description: + name: universal_html + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.8" + universal_io: + dependency: transitive + description: + name: universal_io + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" url_launcher: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index c909939..c93d73f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,6 +37,7 @@ dependencies: url_launcher: ^6.0.10 image: ^3.0.4 screenshot: ^1.2.3 + universal_html: ^2.0.8 # firebase_core: ^1.6.0 # firebase_analytics: "^8.3.2"