[data] migrate to bloc management
This commit is contained in:
parent
ecb537bf12
commit
c25256b13b
|
|
@ -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<DlFormState> {
|
||||
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!);
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Object> get props => [url, format];
|
||||
}
|
||||
|
||||
final class DlFormInitial extends DlFormState {
|
||||
const DlFormInitial();
|
||||
}
|
||||
|
|
@ -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<DlFormState>();
|
||||
return BlocBuilder<DlFormCubit, DlFormState>(builder: (context, state) {
|
||||
final url = state.url;
|
||||
final format = state.format;
|
||||
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Text('Url: ${dlForm.url}'),
|
||||
Text('Format: ${dlForm.format}'),
|
||||
],
|
||||
);
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Text('Url: ${url}'),
|
||||
Text('Format: ${format}'),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String> formatList = <String>[
|
||||
"MP3",
|
||||
|
|
@ -19,7 +19,7 @@ class DropdownFormat extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var dlForm = context.watch<DlFormState>();
|
||||
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<String>(
|
||||
value: dlForm.format,
|
||||
value: dlFormState.format,
|
||||
elevation: 16,
|
||||
style: const TextStyle(color: colorMainWhite),
|
||||
dropdownColor: colorMainBlue,
|
||||
onChanged: (String? value) {
|
||||
dlForm.setFormat(value!);
|
||||
context.read<DlFormCubit>().setFormat(value!);
|
||||
},
|
||||
underline: Container(),
|
||||
items: formatList.map<DropdownMenuItem<String>>((String value) {
|
||||
|
|
@ -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<SubmitButton> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var dlForm = context.watch<DlFormState>();
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints.tightFor(width: 200),
|
||||
child: MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
dlForm.download();
|
||||
context.read<DlFormCubit>().download();
|
||||
},
|
||||
child: InkWell(
|
||||
onHover: (hovering) {
|
||||
|
|
@ -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<DlFormState>();
|
||||
|
||||
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<DlFormCubit>().setUrl(newUrl);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
|
@ -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<AppState>(
|
||||
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<AppState> store;
|
||||
const NoTubeApp({super.key, required this.store});
|
||||
const NoTubeApp({super.key});
|
||||
|
||||
@override
|
||||
State<NoTubeApp> createState() => _NoTubeAppState();
|
||||
|
|
@ -61,24 +51,22 @@ class _NoTubeAppState extends State<NoTubeApp> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StoreProvider<AppState>(
|
||||
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<AppState>(
|
||||
builder: (BuildContext context, Store<AppState> 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())),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<String, dynamic> json) {
|
||||
return Video(
|
||||
id: json['id'],
|
||||
|
|
@ -29,4 +29,8 @@ class Video {
|
|||
uploader: json['uploader'] ?? '',
|
||||
uploadDate: json['upload_date'] ?? '');
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object> get props =>
|
||||
[id, title, thumbnail, description, duration, uploader, uploadDate];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<VideosCubit, VideosState>(
|
||||
listener: (context, state) {},
|
||||
builder: (context, state) {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
for (Video video
|
||||
in context.read<VideosCubit>().videoList)
|
||||
Text(video.title),
|
||||
],
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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<void> download() async {
|
||||
dlService = await DLServices.init();
|
||||
await dlService.analyseUrl(url);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
import 'package:redux/redux.dart';
|
||||
import './app.state.dart';
|
||||
|
||||
List<Middleware<AppState>> appMiddleware() {
|
||||
// final Middleware<AppState> _login = login(_repo);
|
||||
|
||||
return [
|
||||
// TypedMiddleware<AppState, LoginAction>(_login),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -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),
|
||||
);
|
||||
|
|
@ -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 }";
|
||||
}
|
||||
}
|
||||
|
|
@ -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 }';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
import 'package:redux/redux.dart';
|
||||
import 'package:notube/store/app.state.dart';
|
||||
import 'package:notube/models/Video.dart';
|
||||
|
||||
Middleware<AppState> getVideos(Video _video) {
|
||||
return (Store<AppState> 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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import 'package:redux/redux.dart';
|
||||
import 'videos.state.dart';
|
||||
|
||||
final videosReducer = combineReducers<VideosState>([]);
|
||||
|
|
@ -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}";
|
||||
}
|
||||
|
||||
|
|
@ -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<VideosState> {
|
||||
VideosCubit() : super(VideosState());
|
||||
|
||||
final List<Video> _videoList = [];
|
||||
List<Video> get videoList => _videoList;
|
||||
|
||||
void addVideo(Video video) {
|
||||
_videoList.add(video);
|
||||
emit(VideosState(videoList: _videoList));
|
||||
}
|
||||
|
||||
void clearVideos() {
|
||||
_videoList.clear();
|
||||
emit(VideosState(videoList: _videoList));
|
||||
}
|
||||
|
||||
void removeVideo(Video video) {
|
||||
_videoList.remove(video);
|
||||
emit(VideosState(videoList: _videoList));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
part of 'videos_cubit.dart';
|
||||
|
||||
final class VideosState extends Equatable {
|
||||
final List<Video> videoList;
|
||||
|
||||
VideosState({this.videoList = const []});
|
||||
|
||||
@override
|
||||
List<Object> get props => [videoList];
|
||||
}
|
||||
16
pubspec.lock
16
pubspec.lock
|
|
@ -105,6 +105,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
equatable:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: equatable
|
||||
sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -221,6 +229,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.19.0"
|
||||
json_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: json_annotation
|
||||
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.9.0"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
|||
version: 0.0.1+1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.19.4 <4.0.0"
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
|
|
@ -25,6 +25,8 @@ dependencies:
|
|||
redux: ^5.0.0
|
||||
redux_thunk: ^0.4.0
|
||||
flutter_bloc: ^8.1.6
|
||||
equatable: ^2.0.5
|
||||
json_annotation: ^4.9.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
|||
Loading…
Reference in New Issue