From 63228d54dd661301a569c22ed7eb02cd7e428896 Mon Sep 17 00:00:00 2001 From: jscampucci Date: Thu, 20 Jun 2024 08:02:50 +0200 Subject: [PATCH] [data] migrate to bloc management --- lib/dlForm/cubit/dl_form_cubit.dart | 31 ++++++++++ lib/dlForm/cubit/dl_form_state.dart | 28 ++++++++++ lib/{components => dlForm}/dlForm.dart | 31 +++++----- .../formComponents/formatDropdown.dart | 10 ++-- .../formComponents/submitButton.dart | 5 +- .../formComponents/urlTextField.dart | 9 ++- lib/main.dart | 56 ++++++++----------- lib/models/Video.dart | 24 ++++---- lib/screens/home.dart | 18 +++++- lib/services/download.dart | 4 +- lib/states/dlFormState.dart | 25 --------- lib/store/app.middleware.dart | 12 ---- lib/store/app.reducer.dart | 7 --- lib/store/app.state.dart | 28 ---------- lib/store/videos/videos.action.dart | 32 ----------- lib/store/videos/videos.middleware.dart | 15 ----- lib/store/videos/videos.reducer.dart | 4 -- lib/store/videos/videos.state.dart | 28 ---------- lib/videoList/cubit/videos_cubit.dart | 27 +++++++++ lib/videoList/cubit/videos_state.dart | 10 ++++ pubspec.lock | 16 ++++++ pubspec.yaml | 4 +- 22 files changed, 197 insertions(+), 227 deletions(-) create mode 100644 lib/dlForm/cubit/dl_form_cubit.dart create mode 100644 lib/dlForm/cubit/dl_form_state.dart rename lib/{components => dlForm}/dlForm.dart (72%) rename lib/{components => dlForm}/formComponents/formatDropdown.dart (78%) rename lib/{components => dlForm}/formComponents/submitButton.dart (90%) rename lib/{components => dlForm}/formComponents/urlTextField.dart (81%) delete mode 100644 lib/states/dlFormState.dart delete mode 100644 lib/store/app.middleware.dart delete mode 100644 lib/store/app.reducer.dart delete mode 100644 lib/store/app.state.dart delete mode 100644 lib/store/videos/videos.action.dart delete mode 100644 lib/store/videos/videos.middleware.dart delete mode 100644 lib/store/videos/videos.reducer.dart delete mode 100644 lib/store/videos/videos.state.dart create mode 100644 lib/videoList/cubit/videos_cubit.dart create mode 100644 lib/videoList/cubit/videos_state.dart diff --git a/lib/dlForm/cubit/dl_form_cubit.dart b/lib/dlForm/cubit/dl_form_cubit.dart new file mode 100644 index 0000000..06c686e --- /dev/null +++ b/lib/dlForm/cubit/dl_form_cubit.dart @@ -0,0 +1,31 @@ +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:notube/services/download.dart'; + +import 'dart:developer'; + +part 'dl_form_state.dart'; + +class DlFormCubit extends Cubit { + DlFormCubit() : super(DlFormInitial()); + + late DLServices dlService; + + void setFormat(String newFormat) { + emit(state.copyWith( + format: newFormat, + )); + print(newFormat); + } + + void setUrl(String newUrl) { + emit(state.copyWith( + url: newUrl, + )); + } + + void download() async { + dlService = await DLServices.init(); + await dlService.analyseUrl(state.url!); + } +} diff --git a/lib/dlForm/cubit/dl_form_state.dart b/lib/dlForm/cubit/dl_form_state.dart new file mode 100644 index 0000000..63dcb9c --- /dev/null +++ b/lib/dlForm/cubit/dl_form_state.dart @@ -0,0 +1,28 @@ +part of 'dl_form_cubit.dart'; + +class DlFormState extends Equatable { + const DlFormState({ + this.url = '', + this.format = 'MP3', + }); + + final String url; + final String format; + + DlFormState copyWith({ + String? url, + String? format, + }) { + return DlFormState( + url: url ?? this.url, + format: format ?? this.format, + ); + } + + @override + List get props => [url, format]; +} + +final class DlFormInitial extends DlFormState { + const DlFormInitial(); +} diff --git a/lib/components/dlForm.dart b/lib/dlForm/dlForm.dart similarity index 72% rename from lib/components/dlForm.dart rename to lib/dlForm/dlForm.dart index c2650d6..ae5249e 100644 --- a/lib/components/dlForm.dart +++ b/lib/dlForm/dlForm.dart @@ -1,17 +1,17 @@ import 'package:flutter/material.dart'; -import 'package:notube/components/formComponents/formatDropdown.dart'; -import 'package:notube/components/formComponents/submitButton.dart'; -import 'package:notube/components/formComponents/urlTextField.dart'; -import 'package:notube/states/dlFormState.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:notube/dlForm/cubit/dl_form_cubit.dart'; +import 'package:notube/dlForm/formComponents/formatDropdown.dart'; +import 'package:notube/dlForm/formComponents/submitButton.dart'; +import 'package:notube/dlForm/formComponents/urlTextField.dart'; class DlForm extends StatelessWidget { const DlForm({super.key}); @override Widget build(BuildContext context) { - return ChangeNotifierProvider( - create: (context) => DlFormState(), + return BlocProvider( + create: (context) => DlFormCubit(), child: Form(child: LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { if (constraints.maxWidth < 320) { @@ -63,13 +63,16 @@ class DebugDlFormState extends StatelessWidget { @override Widget build(BuildContext context) { - var dlForm = context.watch(); + return BlocBuilder(builder: (context, state) { + final url = state.url; + final format = state.format; - return Column( - children: [ - Text('Url: ${dlForm.url}'), - Text('Format: ${dlForm.format}'), - ], - ); + return Column( + children: [ + Text('Url: ${url}'), + Text('Format: ${format}'), + ], + ); + }); } } diff --git a/lib/components/formComponents/formatDropdown.dart b/lib/dlForm/formComponents/formatDropdown.dart similarity index 78% rename from lib/components/formComponents/formatDropdown.dart rename to lib/dlForm/formComponents/formatDropdown.dart index 6763500..5646fe5 100644 --- a/lib/components/formComponents/formatDropdown.dart +++ b/lib/dlForm/formComponents/formatDropdown.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:notube/constants.dart'; -import 'package:provider/provider.dart'; -import 'package:notube/states/dlFormState.dart'; +import 'package:notube/dlForm/cubit/dl_form_cubit.dart'; const List formatList = [ "MP3", @@ -19,7 +19,7 @@ class DropdownFormat extends StatelessWidget { @override Widget build(BuildContext context) { - var dlForm = context.watch(); + final dlFormState = context.select((DlFormCubit cubit) => cubit.state); return Container( padding: EdgeInsets.symmetric( @@ -29,12 +29,12 @@ class DropdownFormat extends StatelessWidget { // dropdown below.. child: DropdownButton( - value: dlForm.format, + value: dlFormState.format, elevation: 16, style: const TextStyle(color: colorMainWhite), dropdownColor: colorMainBlue, onChanged: (String? value) { - dlForm.setFormat(value!); + context.read().setFormat(value!); }, underline: Container(), items: formatList.map>((String value) { diff --git a/lib/components/formComponents/submitButton.dart b/lib/dlForm/formComponents/submitButton.dart similarity index 90% rename from lib/components/formComponents/submitButton.dart rename to lib/dlForm/formComponents/submitButton.dart index 9de4138..a999a73 100644 --- a/lib/components/formComponents/submitButton.dart +++ b/lib/dlForm/formComponents/submitButton.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:notube/constants.dart'; import 'package:provider/provider.dart'; -import 'package:notube/states/dlFormState.dart'; +import 'package:notube/dlForm/cubit/dl_form_cubit.dart'; class SubmitButton extends StatefulWidget { const SubmitButton({super.key}); @@ -16,14 +16,13 @@ class _SubmitButtonState extends State { @override Widget build(BuildContext context) { - var dlForm = context.watch(); return ConstrainedBox( constraints: BoxConstraints.tightFor(width: 200), child: MouseRegion( cursor: SystemMouseCursors.click, child: GestureDetector( onTap: () { - dlForm.download(); + context.read().download(); }, child: InkWell( onHover: (hovering) { diff --git a/lib/components/formComponents/urlTextField.dart b/lib/dlForm/formComponents/urlTextField.dart similarity index 81% rename from lib/components/formComponents/urlTextField.dart rename to lib/dlForm/formComponents/urlTextField.dart index 797473f..888f64f 100644 --- a/lib/components/formComponents/urlTextField.dart +++ b/lib/dlForm/formComponents/urlTextField.dart @@ -2,15 +2,14 @@ import 'package:flutter/material.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:notube/constants.dart'; import 'package:provider/provider.dart'; -import 'package:notube/states/dlFormState.dart'; +import 'package:notube/dlForm/cubit/dl_form_cubit.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; class UrlTextField extends StatelessWidget { const UrlTextField({super.key}); @override Widget build(BuildContext context) { - var dlForm = context.watch(); - return Flexible( child: TextFormField( decoration: InputDecoration( @@ -28,8 +27,8 @@ class UrlTextField extends StatelessWidget { } return null; }, - onChanged: (value) { - dlForm.setUrl(value); + onChanged: (newUrl) { + context.read().setUrl(newUrl); }, ), ); diff --git a/lib/main.dart b/lib/main.dart index 84a85dc..69e66c5 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,11 +4,9 @@ import 'package:notube/wrapper.dart'; import 'package:notube/constants.dart'; import 'package:window_manager/window_manager.dart'; import 'package:upgrader/upgrader.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; -import 'package:notube/store/app.state.dart'; -import 'package:notube/store/app.reducer.dart'; -import 'package:notube/store/videos/videos.state.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:notube/videoList/cubit/videos_cubit.dart'; +import 'package:notube/models/Video.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -26,25 +24,17 @@ void main() async { await windowManager.focus(); }); - final store = Store( - appReducer, - initialState: AppState( - videosState: VideosState.initial(), - ), - ); - runApp( EasyLocalization( supportedLocales: [Locale('en', 'US'), Locale('fr', 'FR')], path: 'lib/translations', fallbackLocale: Locale('en', 'US'), - child: NoTubeApp(store: store)), + child: NoTubeApp()), ); } class NoTubeApp extends StatefulWidget { - final Store store; - const NoTubeApp({super.key, required this.store}); + const NoTubeApp({super.key}); @override State createState() => _NoTubeAppState(); @@ -61,24 +51,22 @@ class _NoTubeAppState extends State { @override Widget build(BuildContext context) { - return StoreProvider( - store: widget.store, - child: MaterialApp( - title: 'NoTube', - theme: ThemeData( - fontFamily: 'Poppins', - useMaterial3: true, - colorScheme: ColorScheme.fromSeed( - seedColor: colorMainRed, brightness: Brightness.dark), - appBarTheme: const AppBarTheme( - color: colorBackgroundBlack, elevation: 0), - scaffoldBackgroundColor: colorMainGrey), - localizationsDelegates: context.localizationDelegates, - supportedLocales: context.supportedLocales, - locale: context.locale, - home: StoreBuilder( - builder: (BuildContext context, Store store) => - UpgradeAlert(upgrader: upgrader, child: const Wrapper()), - ))); + return MaterialApp( + title: 'NoTube', + theme: ThemeData( + fontFamily: 'Poppins', + useMaterial3: true, + colorScheme: ColorScheme.fromSeed( + seedColor: colorMainRed, brightness: Brightness.dark), + appBarTheme: + const AppBarTheme(color: colorBackgroundBlack, elevation: 0), + scaffoldBackgroundColor: colorMainGrey), + localizationsDelegates: context.localizationDelegates, + supportedLocales: context.supportedLocales, + locale: context.locale, + home: BlocProvider( + create: (context) => VideosCubit(), + child: UpgradeAlert(upgrader: upgrader, child: const Wrapper())), + ); } } diff --git a/lib/models/Video.dart b/lib/models/Video.dart index a4fe910..a409666 100644 --- a/lib/models/Video.dart +++ b/lib/models/Video.dart @@ -1,14 +1,6 @@ -import 'dart:developer' as developer; - -class Video { - String id; - String title; - String thumbnail; - String description; - String duration; - String uploader; - String uploadDate; +import 'package:equatable/equatable.dart'; +class Video extends Equatable { Video({ required this.id, required this.title, @@ -19,6 +11,14 @@ class Video { required this.uploadDate, }); + String id; + String title; + String thumbnail; + String description; + String duration; + String uploader; + String uploadDate; + factory Video.fromJson(Map json) { return Video( id: json['id'], @@ -29,4 +29,8 @@ class Video { uploader: json['uploader'] ?? '', uploadDate: json['upload_date'] ?? ''); } + + @override + List get props => + [id, title, thumbnail, description, duration, uploader, uploadDate]; } diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 5c4ece2..68e42ec 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -1,7 +1,10 @@ import 'package:flutter/material.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:notube/constants.dart'; -import 'package:notube/components/dlForm.dart'; +import 'package:notube/dlForm/dlForm.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:notube/videoList/cubit/videos_cubit.dart'; +import 'package:notube/models/Video.dart'; class Home extends StatelessWidget { Home({super.key}); @@ -28,7 +31,18 @@ class Home extends StatelessWidget { SizedBox(height: 10), Padding( padding: EdgeInsets.symmetric(horizontal: 20), - child: DlForm()) + child: DlForm()), + BlocConsumer( + listener: (context, state) {}, + builder: (context, state) { + return Column( + children: [ + for (Video video + in context.read().videoList) + Text(video.title), + ], + ); + }), ], ), ), diff --git a/lib/services/download.dart b/lib/services/download.dart index efcd119..1abfda0 100644 --- a/lib/services/download.dart +++ b/lib/services/download.dart @@ -4,10 +4,10 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:notube/models/Video.dart'; -import 'package:notube/states/dlFormState.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:notube/videoList/cubit/videos_cubit.dart'; import 'package:path_provider/path_provider.dart'; import 'package:process_run/shell.dart'; -import 'package:provider/provider.dart'; import 'dart:developer'; diff --git a/lib/states/dlFormState.dart b/lib/states/dlFormState.dart deleted file mode 100644 index 882d463..0000000 --- a/lib/states/dlFormState.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:notube/services/download.dart'; - -class DlFormState extends ChangeNotifier { - String url = - 'https://youtu.be/playlist?list=PLk1fi9OrZmvGBdh9BdWIhZImGVDUqls1X'; - String format = 'MP3'; - - late DLServices dlService; - - void setUrl(String newUrl) { - url = newUrl; - notifyListeners(); - } - - void setFormat(String newFormat) { - format = newFormat; - notifyListeners(); - } - - Future download() async { - dlService = await DLServices.init(); - await dlService.analyseUrl(url); - } -} diff --git a/lib/store/app.middleware.dart b/lib/store/app.middleware.dart deleted file mode 100644 index f610b0f..0000000 --- a/lib/store/app.middleware.dart +++ /dev/null @@ -1,12 +0,0 @@ - -import 'package:redux/redux.dart'; -import './app.state.dart'; - -List> appMiddleware() { -// final Middleware _login = login(_repo); - -return [ - // TypedMiddleware(_login), -]; -} - \ No newline at end of file diff --git a/lib/store/app.reducer.dart b/lib/store/app.reducer.dart deleted file mode 100644 index 3d0b405..0000000 --- a/lib/store/app.reducer.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:notube/store/videos/videos.reducer.dart'; - -import './app.state.dart'; - -AppState appReducer(AppState state, action) => AppState( - videosState: videosReducer(state.videosState, action), - ); diff --git a/lib/store/app.state.dart b/lib/store/app.state.dart deleted file mode 100644 index 43e38c8..0000000 --- a/lib/store/app.state.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:notube/store/videos/videos.state.dart'; - -import 'package:flutter/material.dart'; - -class AppState { - final VideosState videosState; - - AppState({required this.videosState}); - - factory AppState.initial() => AppState( - videosState: VideosState.initial(), - ); - - @override - bool operator ==(other) => - identical(this, other) || - other is AppState && - runtimeType == other.runtimeType && - videosState == other.videosState; - - @override - int get hashCode => super.hashCode ^ videosState.hashCode; - - @override - String toString() { - return "AppState { videosState: $videosState }"; - } -} diff --git a/lib/store/videos/videos.action.dart b/lib/store/videos/videos.action.dart deleted file mode 100644 index b860a7a..0000000 --- a/lib/store/videos/videos.action.dart +++ /dev/null @@ -1,32 +0,0 @@ - -import 'package:flutter/material.dart'; - -class VideosAction { - - @override - String toString() { - return 'VideosAction { }'; - } -} - -class VideosSuccessAction { - final int isSuccess; - - VideosSuccessAction({required this.isSuccess}); - @override - String toString() { - return 'VideosSuccessAction { isSuccess: $isSuccess }'; - } -} - -class VideosFailedAction { - final String error; - - VideosFailedAction({required this.error}); - - @override - String toString() { - return 'VideosFailedAction { error: $error }'; - } -} - \ No newline at end of file diff --git a/lib/store/videos/videos.middleware.dart b/lib/store/videos/videos.middleware.dart deleted file mode 100644 index b18b9bd..0000000 --- a/lib/store/videos/videos.middleware.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:redux/redux.dart'; -import 'package:notube/store/app.state.dart'; -import 'package:notube/models/Video.dart'; - -Middleware getVideos(Video _video) { - return (Store store, action, NextDispatcher dispatch) async { - dispatch(action); - try { - // TODO: Write here your middleware logic and api calls - } catch (error) { - // TODO: API Error handling - print(error); - } - }; -} diff --git a/lib/store/videos/videos.reducer.dart b/lib/store/videos/videos.reducer.dart deleted file mode 100644 index 9d68d5e..0000000 --- a/lib/store/videos/videos.reducer.dart +++ /dev/null @@ -1,4 +0,0 @@ -import 'package:redux/redux.dart'; -import 'videos.state.dart'; - -final videosReducer = combineReducers([]); diff --git a/lib/store/videos/videos.state.dart b/lib/store/videos/videos.state.dart deleted file mode 100644 index e386322..0000000 --- a/lib/store/videos/videos.state.dart +++ /dev/null @@ -1,28 +0,0 @@ - -class VideosState { - final bool loading; - final String error; - - VideosState(this.loading, this.error); - - factory VideosState.initial() => VideosState(false, ''); - - VideosState copyWith({bool? loading, String? error}) => - VideosState(loading ?? this.loading, error ?? this.error); - - @override - bool operator ==(other) => - identical(this, other) || - other is VideosState && - runtimeType == other.runtimeType && - loading == other.loading && - error == other.error; - - @override - int get hashCode => - super.hashCode ^ runtimeType.hashCode ^ loading.hashCode ^ error.hashCode; - - @override - String toString() => "VideosState { loading: $loading, error: $error}"; -} - \ No newline at end of file diff --git a/lib/videoList/cubit/videos_cubit.dart b/lib/videoList/cubit/videos_cubit.dart new file mode 100644 index 0000000..7f994f6 --- /dev/null +++ b/lib/videoList/cubit/videos_cubit.dart @@ -0,0 +1,27 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:notube/models/Video.dart'; + +part 'videos_state.dart'; + +class VideosCubit extends Cubit { + VideosCubit() : super(VideosState()); + + final List