API Table Investasi Admin

This commit is contained in:
2025-02-04 22:35:44 +08:00
parent 257c1ebaad
commit c53ca6d355
40 changed files with 1737 additions and 378 deletions

View File

@@ -0,0 +1,16 @@
import 'package:ff_bloc/ff_bloc.dart';
import 'package:${appName}${relative}/index.dart';
class ${upperName}Bloc extends FFBloc<${upperName}Event, ${upperName}State> {
${upperName}Bloc({
required this.provider,
super.initialState = const ${upperName}State(),
});
/// Use this for all requests to backend - you can mock it in tests
final ${upperName}Provider provider;
@override
${upperName}State onErrorState(Object error) => state.copy(error: error, isLoading: false);
}

View File

@@ -0,0 +1,78 @@
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:ff_bloc/ff_bloc.dart';
import 'package:${appName}${relative}/index.dart';
@immutable
abstract class ${upperName}Event implements FFBlocEvent<${upperName}State, ${upperName}Bloc> {}
/// Initial Event with load data
class Load${upperName}Event extends ${upperName}Event {
Load${upperName}Event({required this.id});
final String? id;
static const String _name = 'Load${upperName}Event';
@override
String toString() => _name;
@override
Stream<${upperName}State> applyAsync({required ${upperName}Bloc bloc}) async* {
// set loading true for show loading
yield bloc.state.copyWithoutError(isLoading: true);
// fetch data
final result = await bloc.provider.fetchAsync(id);
// set data to state
yield bloc.state.copyWithoutError(
isLoading: false,
data: ${upperName}ViewModel(items: result),
);
}
}
class Add${upperName}Event extends ${upperName}Event {
static const String _name = 'Add${upperName}Event';
@override
String toString() => _name;
@override
Stream<${upperName}State> applyAsync({required ${upperName}Bloc bloc}) async* {
yield bloc.state.copyWithoutError(isLoading: true);
final result = await bloc.provider.addMore(bloc.state.data?.items);
yield bloc.state.copyWithoutError(
isLoading: false,
data: ${upperName}ViewModel(items: result),
);
}
}
class ErrorYouAwesomeEvent extends YouAwesomeEvent {
static const String _name = 'ErrorYouAwesomeEvent';
@override
String toString() => _name;
@override
Stream<YouAwesomeState> applyAsync({required YouAwesomeBloc bloc}) async* {
throw Exception('Test error');
}
}
class Clear${upperName}Event extends ${upperName}Event {
static const String _name = 'Clear${upperName}Event';
@override
String toString() => _name;
@override
Stream<${upperName}State> applyAsync({required ${upperName}Bloc bloc}) async* {
yield bloc.state.copyWithoutError(isLoading: true);
yield bloc.state.copyWithoutData(
isLoading: false,
);
}
}

View File

View File

@@ -0,0 +1,51 @@
// ignore: depend_on_referenced_packages
import 'package:equatable/equatable.dart';
class ${upperName}Model extends Equatable {
const ${upperName}Model({
required this.name,
});
final String name;
@override
List<Object> get props => [ name];
Map<dynamic, dynamic> toMap() {
return {
'name': name,
};
}
static ${upperName}Model? fromMap(Map<dynamic, dynamic>? map) {
if (map == null) {
return null;
}
return ${upperName}Model(
name: map['name']!.toString(),
);
}
}
class ${upperName}ViewModel extends Equatable {
const ${upperName}ViewModel({
// TODO(all): add all required constructor parameters
required this.items,
});
// TODO(all): declare your fields here
final List<${upperName}Model>? items;
@override
List<Object?> get props => [items /*TODO(all): List all fields here*/];
// TODO(all): implement copyWith
${upperName}ViewModel copyWith({
List<${upperName}Model>? items,
}) {
return ${upperName}ViewModel(
items: items ?? this.items,
);
}
}

View File

@@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:${appName}${relative}/index.dart';
class ${upperName}Page extends StatefulWidget {
const ${upperName}Page({
required this.bloc,
super.key
});
static const String routeName = '/${privateName}';
final ${upperName}Bloc? bloc;
@override
State<${upperName}Page> createState() => _${upperName}PageState();
}
class _${upperName}PageState extends State<${upperName}Page> {
${upperName}Bloc? _bloc;
${upperName}Bloc get bloc {
// get it by DI in real code.
_bloc ??= widget.bloc ?? ${upperName}Bloc();
return _bloc!;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('${upperName}'),
actions: [
IconButton(
icon: const Icon(Icons.error),
onPressed: () {
bloc.add(ErrorYouAwesomeEvent());
},
),
IconButton(
icon: const Icon(Icons.add),
onPressed: () {
bloc.add(Add${upperName}Event());
},
),
IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
bloc.add(Clear${upperName}Event());
},
),
],
),
body: ${upperName}Screen(bloc: bloc),
);
}
}

View File

@@ -0,0 +1,26 @@
import 'dart:async';
import 'package:${appName}${relative}/index.dart';
class ${upperName}Provider {
Future<List<${upperName}Model>?> fetchAsync(String? id) async {
// write logic here to send request to server
if (id == null) {
return null;
}
return [${upperName}Model(name: id)];
}
Future<List<${upperName}Model>?> addMore(List<${upperName}Model>? now) async {
// write logic here to send request to server
final result = [
...(now ?? <${upperName}Model>[]),
${upperName}Model(name: now?.length.toString() ?? '0')
];
return result;
}
}

View File

@@ -0,0 +1,126 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:${appName}${relative}/index.dart';
class ${upperName}Screen extends StatefulWidget {
const ${upperName}Screen({
required this.bloc,
super.key,
}) ;
@protected
final ${upperName}Bloc bloc;
@override
State<${upperName}Screen> createState() {
return ${upperName}ScreenState();
}
}
class ${upperName}ScreenState extends State<${upperName}Screen> {
@override
void initState() {
super.initState();
// load data on init widget if bloc has not data
if (!widget.bloc.state.hasData) {
_load();
}
}
@override
void dispose() {
// dispose bloc if you use subscriptions in bloc
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocBuilder<${upperName}Bloc, ${upperName}State>(
bloc: widget.bloc,
builder: (
BuildContext context,
${upperName}State currentState,
) {
// declaration of bloc states
return currentState.when(
onLoading: ()=>const CircularProgressIndicator(),
onEmpty: (data) => _Empty(),
onData: (data) => _BodyList(data: data),
onError: (e) => Center(
child: Column(
children: [
Text(e.toString()),
TextButton(
onPressed: _load,
child: const Text('ReLoad'),
)
],
),
),
);
},
);
}
void _load() {
widget.bloc.add(Load${upperName}Event(id:'1'));
}
}
class _BodyList extends StatefulWidget {
const _BodyList({required this.data});
final ${upperName}ViewModel data;
@override
State<_BodyList> createState() => _BodyListState();
}
class _BodyListState extends State<_BodyList> {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return CustomScrollView(
// primary: true,
slivers: [
const SliverToBoxAdapter(child: Divider()),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
final item = widget.data.items![index];
if (index == 0) {
return Text('Header $index, id = '+item.name);
}
return Text('Index = $index, id = '+item.name);
},
childCount: widget.data.items!.length,
))]);
}
}
class _Empty extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Text('Empty'),
],
);
}
}

View File

@@ -0,0 +1,15 @@
import 'package:ff_bloc/ff_bloc.dart';
import 'package:${appName}${relative}/index.dart';
class ${upperName}State extends FFState<${upperName}State, ${upperName}ViewModel> {
const ${upperName}State({
super.version = 0,
super.isLoading = false,
super.data,
super.error,
});
@override
StateCopyFactory<${upperName}State, ${upperName}ViewModel> getCopyFactory() => ${upperName}State.new;
}