From a7d2f30721a8b3be8520e405897144297e594a97 Mon Sep 17 00:00:00 2001 From: Knot Date: Wed, 13 Nov 2024 13:32:50 +0700 Subject: [PATCH] add download file --- lib/cubit/home_page_cubit.dart | 91 +++++++++++++- lib/home_page.dart | 212 +++++++-------------------------- lib/raw_code.dart | 165 +++++++++++++++++++++++++ pubspec.lock | 26 +++- pubspec.yaml | 1 + 5 files changed, 322 insertions(+), 173 deletions(-) create mode 100644 lib/raw_code.dart diff --git a/lib/cubit/home_page_cubit.dart b/lib/cubit/home_page_cubit.dart index 1d203ea..4d9076d 100644 --- a/lib/cubit/home_page_cubit.dart +++ b/lib/cubit/home_page_cubit.dart @@ -1,10 +1,95 @@ +import 'dart:convert'; +import 'dart:html' as html; + +import 'package:archive/archive.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_cubit_create_page/cubit/home_page_state.dart'; +import 'package:flutter_cubit_create_page/raw_code.dart'; +import 'package:recase/recase.dart'; class HomePageCubit extends Cubit { - HomePageCubit() : super(const HomePageState()); + final TextEditingController nameTextEditingController = + TextEditingController(); + + HomePageCubit() : super(const HomePageState()) { + nameTextEditingController.addListener(() { + final name = nameTextEditingController.text; + emit(state.copyWith(name: name)); + }); + + nameTextEditingController.text = 'Home'; + } + + @override + Future close() { + nameTextEditingController.dispose(); + return super.close(); + } + + void setName(String name) {} + + void onTapDownload() { + final nameTitleCase = state.name.titleCase; + final namePascalCase = state.name.pascalCase; + final nameSnakeCase = state.name.snakeCase; + + final pageStateFileBytes = utf8.encode( + RawCode.pageState( + nameSnakeCase: nameSnakeCase, + namePascalCase: namePascalCase, + ), + ); + + final pageCubitFileBytes = utf8.encode( + RawCode.pageCubit( + nameSnakeCase: nameSnakeCase, + namePascalCase: namePascalCase, + ), + ); + + final pageFileBytes = utf8.encode( + RawCode.page( + nameSnakeCase: nameSnakeCase, + namePascalCase: namePascalCase, + nameTitleCase: nameTitleCase, + ), + ); + + final archive = Archive(); + + archive.addFile( + ArchiveFile( + 'cubit/${nameSnakeCase}_page_state.dart', + pageStateFileBytes.length, + pageStateFileBytes, + ), + ); + archive.addFile( + ArchiveFile( + 'cubit/${nameSnakeCase}_page_cubit.dart', + pageCubitFileBytes.length, + pageCubitFileBytes, + ), + ); + + archive.addFile( + ArchiveFile( + '${state.name.snakeCase}_page.dart', + pageFileBytes.length, + pageFileBytes, + ), + ); + + final zippedData = ZipEncoder().encode(archive)!; + final blob = html.Blob([Uint8List.fromList(zippedData)], 'application/zip'); + final url = html.Url.createObjectUrlFromBlob(blob); + + html.AnchorElement(href: url) + ..setAttribute('download', '$nameSnakeCase.zip') + ..click(); - void setName(String name) { - emit(state.copyWith(name: name)); + html.Url.revokeObjectUrl(url); } } diff --git a/lib/home_page.dart b/lib/home_page.dart index 92761e1..5c5b8cd 100644 --- a/lib/home_page.dart +++ b/lib/home_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_cubit_create_page/cubit/home_page_cubit.dart'; import 'package:flutter_cubit_create_page/cubit/home_page_state.dart'; +import 'package:flutter_cubit_create_page/raw_code.dart'; import 'package:recase/recase.dart'; import 'package:syntax_highlight/syntax_highlight.dart'; @@ -38,31 +39,21 @@ class HomeView extends StatefulWidget { } class _HomeViewState extends State { + HomePageCubit get _cubit { + return context.read(); + } + final ScrollController _scrollController = ScrollController(); final ScrollController _stateScrollController = ScrollController(); final ScrollController _cubitScrollController = ScrollController(); final ScrollController _pageScrollController = ScrollController(); - final TextEditingController _nameTextEditingController = - TextEditingController(); - - @override - void initState() { - super.initState(); - _nameTextEditingController.addListener(() { - final name = _nameTextEditingController.text; - context.read().setName(name); - }); - _nameTextEditingController.text = 'Home'; - } - @override void dispose() { _scrollController.dispose(); _stateScrollController.dispose(); _cubitScrollController.dispose(); _pageScrollController.dispose(); - _nameTextEditingController.dispose(); super.dispose(); } @@ -112,159 +103,29 @@ class _HomeViewState extends State { _code( controller: _stateScrollController, fileName: '${nameSnakeCase}_page_state.dart', - code: ''' -import 'package:equatable/equatable.dart'; - -enum ${namePascalCase}PageStatus { - initial, - loading, - ready, - failure, - ; - - bool get isLoading => this == ${namePascalCase}PageStatus.loading; -} - -class ${namePascalCase}PageState extends Equatable { - final ${namePascalCase}PageStatus status; - final Object? error; - - const ${namePascalCase}PageState({ - this.status = ${namePascalCase}PageStatus.initial, - this.error, - }); - - @override - List get props => [ - status, - error, - ]; - - ${namePascalCase}PageState copyWith({ - ${namePascalCase}PageStatus? status, - Object? error, - }) { - return ${namePascalCase}PageState( - status: status ?? this.status, - error: error ?? this.error, - ); - } - - ${namePascalCase}PageState loading() { - return copyWith( - status: ${namePascalCase}PageStatus.loading, - ); - } - - ${namePascalCase}PageState ready() { - return copyWith( - status: ${namePascalCase}PageStatus.ready, - ); - } - - ${namePascalCase}PageState failure( - Object error, - ) { - return copyWith( - status: ${namePascalCase}PageStatus.failure, - error: error, - ); - } -} -''', + code: RawCode.pageState( + nameSnakeCase: nameSnakeCase, + namePascalCase: namePascalCase, + ), ), const SizedBox(height: 16), _code( controller: _cubitScrollController, fileName: '${nameSnakeCase}_page_cubit.dart', - code: ''' -import 'package:flutter_bloc/flutter_bloc.dart'; - -import '${nameSnakeCase}_page_state.dart'; - -class ${namePascalCase}PageCubit extends Cubit<${namePascalCase}PageState> { - bool _mounted = true; - - ${namePascalCase}PageCubit() : super(const ${namePascalCase}PageState()); - - @override - Future close() { - _mounted = false; - return super.close(); - } - - void _emit(${namePascalCase}PageState newState) { - if (_mounted) emit(newState); - } -} -''', + code: RawCode.pageCubit( + nameSnakeCase: nameSnakeCase, + namePascalCase: namePascalCase, + ), ), const SizedBox(height: 16), _code( controller: _pageScrollController, fileName: '${state.name.snakeCase}_page.dart', - code: ''' -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -import 'cubit/${nameSnakeCase}_page_cubit.dart'; -import 'cubit/${nameSnakeCase}_page_state.dart'; - -class ${namePascalCase}Page extends StatelessWidget { - const ${namePascalCase}Page({super.key}); - - @override - Widget build(BuildContext context) { - return BlocProvider( - create: (context) => ${namePascalCase}PageCubit(), - child: const ${namePascalCase}View(), - ); - } -} - -class ${namePascalCase}View extends StatefulWidget { - const ${namePascalCase}View({super.key}); - - @override - State<${namePascalCase}View> createState() => _${namePascalCase}ViewState(); -} - -class _${namePascalCase}ViewState extends State<${namePascalCase}View> { - ${namePascalCase}PageCubit get _cubit { - return context.read<${namePascalCase}PageCubit>(); - } - - @override - Widget build(BuildContext context) { - return BlocConsumer<${namePascalCase}PageCubit, ${namePascalCase}PageState>( - builder: (context, state) { - return Scaffold( - appBar: AppBar( - title: const Text('$nameTitleCase'), - centerTitle: true, - ), - body: const Center( - child: Text('$nameTitleCase'), + code: RawCode.page( + nameSnakeCase: nameSnakeCase, + namePascalCase: namePascalCase, + nameTitleCase: nameTitleCase, ), - ); - }, - listener: _listener, - ); - } - - void _listener(BuildContext context, ${namePascalCase}PageState state) { - switch (state.status) { - case ${namePascalCase}PageStatus.initial: - case ${namePascalCase}PageStatus.loading: - case ${namePascalCase}PageStatus.ready: - break; - - case ${namePascalCase}PageStatus.failure: - break; - } - } -} -''', ), ], ); @@ -274,21 +135,34 @@ class _${namePascalCase}ViewState extends State<${namePascalCase}View> { return Card( child: Padding( padding: const EdgeInsets.all(16), - child: TextField( - controller: _nameTextEditingController, - style: const TextStyle( - fontFamily: 'Consolas', - ), - maxLines: 1, - decoration: InputDecoration( - labelText: 'Name', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: const BorderSide( - width: 1, + child: Row( + children: [ + Expanded( + child: TextField( + controller: _cubit.nameTextEditingController, + style: const TextStyle( + fontFamily: 'Consolas', + ), + maxLines: 1, + decoration: InputDecoration( + labelText: 'Name', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: const BorderSide( + width: 1, + ), + ), + ), ), ), - ), + const SizedBox(width: 16), + IconButton.filledTonal( + onPressed: _cubit.onTapDownload, + icon: const Icon( + Icons.download, + ), + ), + ], ), ), ); diff --git a/lib/raw_code.dart b/lib/raw_code.dart new file mode 100644 index 0000000..a4a7a3d --- /dev/null +++ b/lib/raw_code.dart @@ -0,0 +1,165 @@ +class RawCode { + RawCode._(); + + static String pageState({ + required String nameSnakeCase, + required String namePascalCase, + }) { + return ''' +import 'package:equatable/equatable.dart'; + +enum ${namePascalCase}PageStatus { + initial, + loading, + ready, + failure, + ; + + bool get isLoading => this == ${namePascalCase}PageStatus.loading; +} + +class ${namePascalCase}PageState extends Equatable { + final ${namePascalCase}PageStatus status; + final Object? error; + + const ${namePascalCase}PageState({ + this.status = ${namePascalCase}PageStatus.initial, + this.error, + }); + + @override + List get props => [ + status, + error, + ]; + + ${namePascalCase}PageState copyWith({ + ${namePascalCase}PageStatus? status, + Object? error, + }) { + return ${namePascalCase}PageState( + status: status ?? this.status, + error: error ?? this.error, + ); + } + + ${namePascalCase}PageState loading() { + return copyWith( + status: ${namePascalCase}PageStatus.loading, + ); + } + + ${namePascalCase}PageState ready() { + return copyWith( + status: ${namePascalCase}PageStatus.ready, + ); + } + + ${namePascalCase}PageState failure( + Object error, + ) { + return copyWith( + status: ${namePascalCase}PageStatus.failure, + error: error, + ); + } +} +'''; + } + + static String pageCubit({ + required String nameSnakeCase, + required String namePascalCase, + }) { + return ''' +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '${nameSnakeCase}_page_state.dart'; + +class ${namePascalCase}PageCubit extends Cubit<${namePascalCase}PageState> { + bool _mounted = true; + + ${namePascalCase}PageCubit() : super(const ${namePascalCase}PageState()); + + @override + Future close() { + _mounted = false; + return super.close(); + } + + void _emit(${namePascalCase}PageState newState) { + if (_mounted) emit(newState); + } +} +'''; + } + + static String page({ + required String nameSnakeCase, + required String namePascalCase, + required String nameTitleCase, + }) { + return ''' +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'cubit/${nameSnakeCase}_page_cubit.dart'; +import 'cubit/${nameSnakeCase}_page_state.dart'; + +class ${namePascalCase}Page extends StatelessWidget { + const ${namePascalCase}Page({super.key}); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => ${namePascalCase}PageCubit(), + child: const ${namePascalCase}View(), + ); + } +} + +class ${namePascalCase}View extends StatefulWidget { + const ${namePascalCase}View({super.key}); + + @override + State<${namePascalCase}View> createState() => _${namePascalCase}ViewState(); +} + +class _${namePascalCase}ViewState extends State<${namePascalCase}View> { + ${namePascalCase}PageCubit get _cubit { + return context.read<${namePascalCase}PageCubit>(); + } + + @override + Widget build(BuildContext context) { + return BlocConsumer<${namePascalCase}PageCubit, ${namePascalCase}PageState>( + builder: (context, state) { + return Scaffold( + appBar: AppBar( + title: const Text('$nameTitleCase'), + centerTitle: true, + ), + body: const Center( + child: Text('$nameTitleCase'), + ), + ); + }, + listener: _listener, + ); + } + + void _listener(BuildContext context, ${namePascalCase}PageState state) { + switch (state.status) { + case ${namePascalCase}PageStatus.initial: + case ${namePascalCase}PageStatus.loading: + case ${namePascalCase}PageStatus.ready: + break; + + case ${namePascalCase}PageStatus.failure: + break; + } + } +} +'''; + } +} diff --git a/pubspec.lock b/pubspec.lock index 919042f..f6536dd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + archive: + dependency: "direct main" + description: + name: archive + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + url: "https://pub.dev" + source: hosted + version: "3.6.1" async: dependency: transitive description: @@ -49,6 +57,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + crypto: + dependency: transitive + description: + name: crypto + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" + source: hosted + version: "3.0.6" cupertino_icons: dependency: "direct main" description: @@ -248,6 +264,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" vector_math: dependency: transitive description: @@ -265,5 +289,5 @@ packages: source: hosted version: "14.2.5" sdks: - dart: ">=3.4.4 <4.0.0" + dart: ">=3.5.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/pubspec.yaml b/pubspec.yaml index 0c132c0..26a0e3a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,6 +14,7 @@ dependencies: flutter_bloc: ^8.1.6 recase: ^4.1.0 syntax_highlight: ^0.4.0 + archive: ^3.6.1 dev_dependencies: flutter_test: