Fakultas Ilmu Komputer UI

Commit 8ec962cd authored by Tsamara Esperanti Erwin's avatar Tsamara Esperanti Erwin 🦄
Browse files

Merge branch 'PBI-7-Progress_Program' into 'staging'

Pbi 7 progress program

add progress program, increase coverage

See merge request !88
parents 0d106b71 013ec5f0
Pipeline #61046 passed with stages
in 31 minutes and 22 seconds
...@@ -6,7 +6,7 @@ String formatDate(DateTime dateTime) { ...@@ -6,7 +6,7 @@ String formatDate(DateTime dateTime) {
} }
String formatDatePlusOne(DateTime dateTime) { String formatDatePlusOne(DateTime dateTime) {
var addOneDay = dateTime.add(Duration(days: 1)); final addOneDay = dateTime.add(const Duration(days: 1));
final formatter = DateFormat(DateFormat.YEAR_MONTH_DAY); final formatter = DateFormat(DateFormat.YEAR_MONTH_DAY);
return dateTime != null ? formatter.format(addOneDay.toLocal()) : ''; return dateTime != null ? formatter.format(addOneDay.toLocal()) : '';
} }
......
...@@ -31,6 +31,8 @@ import 'package:home_industry/Pages/Transactions/repositories/transaction_reposi ...@@ -31,6 +31,8 @@ import 'package:home_industry/Pages/Transactions/repositories/transaction_reposi
import 'package:home_industry/State/Auth/repositories/depedencies_repositories.dart'; import 'package:home_industry/State/Auth/repositories/depedencies_repositories.dart';
import 'package:home_industry/State/ChangeBottomNavigatonBar/bloc.dart'; import 'package:home_industry/State/ChangeBottomNavigatonBar/bloc.dart';
import '../Pages/Program/repositories/program_repository.dart';
class Router { class Router {
static const registerPage = '/register'; static const registerPage = '/register';
static const editProfilePage = '/edit-profile'; static const editProfilePage = '/edit-profile';
...@@ -147,14 +149,29 @@ class Router { ...@@ -147,14 +149,29 @@ class Router {
case programs: case programs:
return MaterialPageRoute<Programs>( return MaterialPageRoute<Programs>(
builder: (context) => const Programs()); builder: (context) => RepositoryProvider<ProgramRepository>.value(
value: ProgramRepository(
dio:
RepositoryProvider.of<DependenciesRepositories>(
context)
.dio),
child: Programs()
));
case detailProgramPage: case detailProgramPage:
final Map<String, dynamic> args = settings.arguments; final Map<String, dynamic> args = settings.arguments;
return MaterialPageRoute<DetailProgram>( return MaterialPageRoute<DetailProgram>(
builder: (context) => DetailProgram( builder: (context) => RepositoryProvider<ProgramRepository>.value(
program: args['program'], value: ProgramRepository(
)); dio:
RepositoryProvider.of<DependenciesRepositories>(
context)
.dio),
child: DetailProgram(
program: args['program'],
),
));
case donationPage: case donationPage:
final Map<String, dynamic> args = settings.arguments; final Map<String, dynamic> args = settings.arguments;
......
...@@ -43,7 +43,6 @@ class ChooseDonationDialog extends StatelessWidget { ...@@ -43,7 +43,6 @@ class ChooseDonationDialog extends StatelessWidget {
class _ChooseDonation extends StatefulWidget { class _ChooseDonation extends StatefulWidget {
final Program program; final Program program;
// const _ChooseDonation(this.program);
const _ChooseDonation({Key key, @required this.program}) : super(key: key); const _ChooseDonation({Key key, @required this.program}) : super(key: key);
@override @override
...@@ -59,6 +58,7 @@ class __ChooseDonationState extends State<_ChooseDonation> { ...@@ -59,6 +58,7 @@ class __ChooseDonationState extends State<_ChooseDonation> {
return Column( return Column(
children: [ children: [
CheckboxListTile( CheckboxListTile(
key: const Key('uang'),
dense: true, dense: true,
controlAffinity: ListTileControlAffinity.leading, controlAffinity: ListTileControlAffinity.leading,
value: uangValue, value: uangValue,
...@@ -74,6 +74,7 @@ class __ChooseDonationState extends State<_ChooseDonation> { ...@@ -74,6 +74,7 @@ class __ChooseDonationState extends State<_ChooseDonation> {
}); });
}), }),
CheckboxListTile( CheckboxListTile(
key: const Key('barang'),
dense: true, dense: true,
controlAffinity: ListTileControlAffinity.leading, controlAffinity: ListTileControlAffinity.leading,
title: Text('Barang', title: Text('Barang',
......
...@@ -39,10 +39,10 @@ class _DonasiBarangState extends State<DonasiBarang> { ...@@ -39,10 +39,10 @@ class _DonasiBarangState extends State<DonasiBarang> {
void onTap( void onTap(
{@required String quantity, {@required String quantity,
@required String description, @required String description,
@required String methodOfDelivery, @required String methodOfDelivery,
@required bool isFinal, @required bool isFinal,
String address}) { String address}) {
goodsDonationBloc.add(GoodsDonationButtonClicked( goodsDonationBloc.add(GoodsDonationButtonClicked(
program: widget.program.id, program: widget.program.id,
quantity: quantity, quantity: quantity,
...@@ -110,7 +110,7 @@ class _DonasiBarangState extends State<DonasiBarang> { ...@@ -110,7 +110,7 @@ class _DonasiBarangState extends State<DonasiBarang> {
), ),
), ),
Container( Container(
margin: EdgeInsets.symmetric(horizontal: 20.0), margin: const EdgeInsets.symmetric(horizontal: 20.0),
child: Form( child: Form(
key: _formKey, key: _formKey,
child: Column( child: Column(
...@@ -120,7 +120,7 @@ class _DonasiBarangState extends State<DonasiBarang> { ...@@ -120,7 +120,7 @@ class _DonasiBarangState extends State<DonasiBarang> {
Row( Row(
children: [ children: [
Radio( Radio(
key: Key('PCK-button'), key: const Key('PCK-button'),
value: 'PCK', value: 'PCK',
groupValue: methodOfDelivery, groupValue: methodOfDelivery,
onChanged: (val) { onChanged: (val) {
...@@ -128,7 +128,7 @@ class _DonasiBarangState extends State<DonasiBarang> { ...@@ -128,7 +128,7 @@ class _DonasiBarangState extends State<DonasiBarang> {
methodOfDelivery = val; methodOfDelivery = val;
deliveryWidget = Row( deliveryWidget = Row(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment.start,
children: [ children: [
RichText( RichText(
text: TextSpan( text: TextSpan(
...@@ -144,8 +144,8 @@ class _DonasiBarangState extends State<DonasiBarang> { ...@@ -144,8 +144,8 @@ class _DonasiBarangState extends State<DonasiBarang> {
.textTheme .textTheme
.bodyText2 .bodyText2
.copyWith( .copyWith(
fontSize: 18, fontSize: 18,
color: Colors.red)), color: Colors.red)),
], ],
), ),
), ),
...@@ -157,7 +157,7 @@ class _DonasiBarangState extends State<DonasiBarang> { ...@@ -157,7 +157,7 @@ class _DonasiBarangState extends State<DonasiBarang> {
child: TextFormField( child: TextFormField(
controller: addressController, controller: addressController,
keyboardType: keyboardType:
TextInputType.multiline, TextInputType.multiline,
validator: (value) { validator: (value) {
if (value.isEmpty) { if (value.isEmpty) {
return 'Mohon isi alamat'; return 'Mohon isi alamat';
...@@ -179,7 +179,7 @@ class _DonasiBarangState extends State<DonasiBarang> { ...@@ -179,7 +179,7 @@ class _DonasiBarangState extends State<DonasiBarang> {
.copyWith(fontSize: 18), .copyWith(fontSize: 18),
), ),
Radio( Radio(
key: Key('DLV-button'), key: const Key('DLV-button'),
value: 'DLV', value: 'DLV',
groupValue: methodOfDelivery, groupValue: methodOfDelivery,
onChanged: (val) { onChanged: (val) {
...@@ -217,7 +217,7 @@ class _DonasiBarangState extends State<DonasiBarang> { ...@@ -217,7 +217,7 @@ class _DonasiBarangState extends State<DonasiBarang> {
setState(() { setState(() {
deliveryWidget = Container( deliveryWidget = Container(
height: 80, height: 80,
child: Text( child: const Text(
'Mohon pilih metode pengiriman', 'Mohon pilih metode pengiriman',
style: TextStyle(color: Colors.red), style: TextStyle(color: Colors.red),
), ),
...@@ -252,20 +252,20 @@ class _DonasiBarangState extends State<DonasiBarang> { ...@@ -252,20 +252,20 @@ class _DonasiBarangState extends State<DonasiBarang> {
borderRadius: BorderRadius.circular(50)), borderRadius: BorderRadius.circular(50)),
child: Center( child: Center(
child: Text( child: Text(
'DONASI SEKARANG', 'DONASI SEKARANG',
style: Theme.of(context).textTheme.bodyText2.copyWith( style: Theme.of(context).textTheme.bodyText2.copyWith(
fontSize: 18, fontSize: 18,
color: Colors.white, color: Colors.white,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
letterSpacing: 1.2), letterSpacing: 1.2),
)), )),
), ),
), ),
); );
} }
List<Widget> _getGoodsForm(){ List<Widget> _getGoodsForm(){
var goodsTextFields = <Widget>[]; final goodsTextFields = <Widget>[];
for(var i = 0; i < goodsDescList.length; i++){ for(var i = 0; i < goodsDescList.length; i++){
goodsTextFields.add( goodsTextFields.add(
Padding( Padding(
...@@ -286,30 +286,30 @@ class _DonasiBarangState extends State<DonasiBarang> { ...@@ -286,30 +286,30 @@ class _DonasiBarangState extends State<DonasiBarang> {
return Padding( return Padding(
padding: const EdgeInsets.only(top: 15.0), padding: const EdgeInsets.only(top: 15.0),
child: Row( child: Row(
children: [ children: [
Container( Container(
width: MediaQuery.of(context).size.width - 80, width: MediaQuery.of(context).size.width - 80,
child: Divider(color: Colors.grey)), child: Divider(color: Colors.grey)),
const SizedBox(width: 10.0,), const SizedBox(width: 10.0,),
InkWell( InkWell(
key: Key('addRemoveButton' + index.toString()), key: Key('addRemoveButton$index'),
onTap: (){ onTap: (){
if(add){ if(add){
goodsDescList.insert(index+1, null); goodsDescList.insert(index+1, null);
goodsQtyList.insert(index+1, null); goodsQtyList.insert(index+1, null);
} }
else { else {
goodsDescList.removeAt(index); goodsDescList.removeAt(index);
goodsQtyList.removeAt(index); goodsQtyList.removeAt(index);
} }
setState((){}); setState((){});
}, },
child: Icon( child: Icon(
(add) ? Icons.add_circle : Icons.remove_circle, add ? Icons.add_circle : Icons.remove_circle,
color: Color.fromRGBO(60, 141, 188, 1), color: const Color.fromRGBO(60, 141, 188, 1),
), ),
) )
], ],
), ),
); );
} }
...@@ -317,7 +317,7 @@ class _DonasiBarangState extends State<DonasiBarang> { ...@@ -317,7 +317,7 @@ class _DonasiBarangState extends State<DonasiBarang> {
class GoodsForm extends StatefulWidget { class GoodsForm extends StatefulWidget {
final int index; final int index;
GoodsForm({Key key, @required this.index}) const GoodsForm({Key key, @required this.index})
: super(key: key); : super(key: key);
@override @override
...@@ -362,7 +362,7 @@ class _GoodsFormState extends State<GoodsForm> { ...@@ -362,7 +362,7 @@ class _GoodsFormState extends State<GoodsForm> {
width: 187, width: 187,
height: 50, height: 50,
child: TextFormField( child: TextFormField(
key: Key('goods-desc'), key: const Key('goods-desc'),
onChanged: (v) => _DonasiBarangState.goodsDescList[widget.index] = v, onChanged: (v) => _DonasiBarangState.goodsDescList[widget.index] = v,
controller: _goodsDescriptionController, controller: _goodsDescriptionController,
validator: (value) { validator: (value) {
...@@ -403,7 +403,7 @@ class _GoodsFormState extends State<GoodsForm> { ...@@ -403,7 +403,7 @@ class _GoodsFormState extends State<GoodsForm> {
height: 50, height: 50,
color: Colors.white, color: Colors.white,
child: TextFormField( child: TextFormField(
key: Key('goods-qty'), key: const Key('goods-qty'),
onChanged: (v) => _DonasiBarangState.goodsQtyList[widget.index] = v, onChanged: (v) => _DonasiBarangState.goodsQtyList[widget.index] = v,
controller: _goodsQuantityController, controller: _goodsQuantityController,
validator: (value) { validator: (value) {
...@@ -433,4 +433,4 @@ InputDecoration _inputDecoration() { ...@@ -433,4 +433,4 @@ InputDecoration _inputDecoration() {
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Color.fromRGBO(224, 225, 226, 1))), borderSide: BorderSide(color: Color.fromRGBO(224, 225, 226, 1))),
); );
} }
\ No newline at end of file
...@@ -61,13 +61,13 @@ class OTPPage extends StatelessWidget { ...@@ -61,13 +61,13 @@ class OTPPage extends StatelessWidget {
children: <Widget>[ children: <Widget>[
const Text('Mohon masukkan OTP yang dikirim ke nomor anda', const Text('Mohon masukkan OTP yang dikirim ke nomor anda',
softWrap: true), softWrap: true),
Divider( const Divider(
height: 20, height: 20,
thickness: null, thickness: null,
), ),
Theme( Theme(
data: Theme.of(context) data: Theme.of(context)
.copyWith(inputDecorationTheme: InputDecorationTheme()), .copyWith(inputDecorationTheme: const InputDecorationTheme()),
child: PinPut( child: PinPut(
onSubmit: (String pin) { onSubmit: (String pin) {
_otpSubmitted(pin, context); _otpSubmitted(pin, context);
...@@ -85,7 +85,7 @@ class OTPPage extends StatelessWidget { ...@@ -85,7 +85,7 @@ class OTPPage extends StatelessWidget {
), ),
), ),
Container( Container(
margin: EdgeInsets.only(top: 10), margin: const EdgeInsets.only(top: 10),
height: MediaQuery.of(context).size.height / 18, height: MediaQuery.of(context).size.height / 18,
child: ButtonResendOTP( child: ButtonResendOTP(
label: 'Kirim Ulang OTP', label: 'Kirim Ulang OTP',
......
...@@ -12,7 +12,7 @@ abstract class SearchProductState extends Equatable { ...@@ -12,7 +12,7 @@ abstract class SearchProductState extends Equatable {
} }
class InitialSearchProductState extends SearchProductState { class InitialSearchProductState extends SearchProductState {
const InitialSearchProductState() : super(0, '', hasReachedMax: true); const InitialSearchProductState({hasReachedMax}) : super(0, '', hasReachedMax: true);
@override @override
List<Object> get props => [page, searchQuery]; List<Object> get props => [page, searchQuery];
......
...@@ -20,6 +20,9 @@ class ProgramBloc extends Bloc<ProgramEvent, ProgramState> { ...@@ -20,6 +20,9 @@ class ProgramBloc extends Bloc<ProgramEvent, ProgramState> {
bool _hasReachedMax(ProgramState state) => bool _hasReachedMax(ProgramState state) =>
state is ListProgramsLoaded && state.hasReachedMax; state is ListProgramsLoaded && state.hasReachedMax;
bool _hasReachedMaxSorted(ProgramState state) =>
state is ListProgramsSortedLoaded && state.hasReachedMax;
@override @override
Stream<ProgramState> mapEventToState( Stream<ProgramState> mapEventToState(
ProgramEvent event, ProgramEvent event,
...@@ -48,6 +51,30 @@ class ProgramBloc extends Bloc<ProgramEvent, ProgramState> { ...@@ -48,6 +51,30 @@ class ProgramBloc extends Bloc<ProgramEvent, ProgramState> {
} catch (e) { } catch (e) {
yield ListProgramsError(error: e.toString()); yield ListProgramsError(error: e.toString());
} }
} else if ((event is FetchProgramByStatus) && !_hasReachedMaxSorted(currentState)) {
try {
var programs =
await programRepository.fetchProgram(page: currentState.page + 1);
if (currentState is ListProgramsLoaded || currentState is InitialListProgramState) {
programs.results.sort((a,b) => b.endDateTime.compareTo(a.endDateTime));
yield ListProgramsSortedLoaded(
programs: programs.results,
hasReachedMax: programs.next == null,
page: currentState.page + 1);
return;
} else if (currentState is ListProgramsSortedLoaded) {
programs.results.sort((a,b) => b.endDateTime.compareTo(a.endDateTime));
yield ListProgramsSortedLoaded(
programs: currentState.programs + programs.results,
hasReachedMax: programs.next == null,
page: currentState.page + 1);
return;
}
} on DioError catch (e) {
yield ListProgramsError(error: e.response.data.toString());
} catch (e) {
yield ListProgramsError(error: e.toString());
}
} }
} }
......
...@@ -10,3 +10,10 @@ class FetchProgram extends ProgramEvent { ...@@ -10,3 +10,10 @@ class FetchProgram extends ProgramEvent {
@override @override
List<Object> get props => []; List<Object> get props => [];
} }
class FetchProgramByStatus extends ProgramEvent {
const FetchProgramByStatus();
@override
List<Object> get props => [];
}
...@@ -26,6 +26,18 @@ class ListProgramsLoaded extends ProgramState { ...@@ -26,6 +26,18 @@ class ListProgramsLoaded extends ProgramState {
List<Object> get props => [programs, hasReachedMax, page]; List<Object> get props => [programs, hasReachedMax, page];
} }
class ListProgramsSortedLoaded extends ProgramState {
final List<Program> programs;
final bool hasReachedMax;
const ListProgramsSortedLoaded(
{@required this.programs, @required this.hasReachedMax, @required page})
: super(page);
@override
List<Object> get props => [programs, hasReachedMax, page];
}
class ListProgramsError extends ProgramState { class ListProgramsError extends ProgramState {
final String error; final String error;
const ListProgramsError({@required this.error}) : super(0); const ListProgramsError({@required this.error}) : super(0);
...@@ -33,3 +45,13 @@ class ListProgramsError extends ProgramState { ...@@ -33,3 +45,13 @@ class ListProgramsError extends ProgramState {
@override @override
List<Object> get props => [page]; List<Object> get props => [page];
} }
class ListProgramsSortedError extends ProgramState {
final String error;
const ListProgramsSortedError({@required this.error}) : super(0);
@override
List<Object> get props => [page];
}
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:dio/dio.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
import 'package:home_industry/Pages/Program/model/program.dart';
import 'package:home_industry/Pages/Program/repositories/program_repository.dart';
part 'progress_program_event.dart';
part 'progress_program_state.dart';
class ProgressProgramBloc extends Bloc<ProgressProgramEvent, ProgressProgramState> {
final Program program;
final ProgramRepository progressProgramRepository;
ProgressProgramBloc({@required this.progressProgramRepository, @required this.program})
: assert(progressProgramRepository != null);
@override
ProgressProgramState get initialState => const ProgressProgramInitial();
@override
Stream<ProgressProgramState> mapEventToState(ProgressProgramEvent event) async* {
if (event is FetchProgressProgram) {
try {
final progressProgram = await progressProgramRepository.fetchProgressProgram(program.id);
yield ProgressProgramLoaded(progressProgram);
} on DioError catch (_) {
yield ProgressProgramError(error: _.response.toString());
}
}
}
}
\ No newline at end of file
part of 'progress_program_bloc.dart';
abstract class ProgressProgramEvent extends Equatable {
const ProgressProgramEvent();
}
class FetchProgressProgram extends ProgressProgramEvent {
const FetchProgressProgram();
@override
List<Object> get props => [];
}
part of 'progress_program_bloc.dart';
abstract class ProgressProgramState extends Equatable {
const ProgressProgramState();
}
class ProgressProgramInitial extends ProgressProgramState {
const ProgressProgramInitial();
@override
List<Object> get props => [];
}
class ProgressProgramLoaded extends ProgressProgramState {
final List<dynamic> progressList;
const ProgressProgramLoaded(this.progressList);