Fakultas Ilmu Komputer UI

Commit b7e363c0 authored by Michael Wiryadinata Halim's avatar Michael Wiryadinata Halim
Browse files

Resolve "Add choices bank transaction"

parent 1edfb30a
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:home_industry/Pages/ProductPayment/model/account.dart';
import 'package:home_industry/Pages/ProductPayment/repositories/rekening_repository.dart';
import 'package:home_industry/State/Auth/repositories/depedencies_repositories.dart';
import 'custom_circular.dart';
class Rekening extends StatefulWidget {
const Rekening({Key key}) : super(key: key);
@override
_RekeningState createState() => _RekeningState();
}
class _RekeningState extends State<Rekening> {
Future<Account> _futureAccount;
@override
void initState() {
final _accountRepository = AccountRepository(
RepositoryProvider.of<DependenciesRepositories>(context).dio);
_futureAccount = _accountRepository.fetchAccountDetail();
super.initState();
}
@override
Widget build(BuildContext context) {
return FutureBuilder<Account>(
future: _futureAccount,
builder: (BuildContext context, AsyncSnapshot<Account> snapshot) {
if (snapshot.hasError) {
return const Center(
child: Text('Maaf sedang ada error pada aplikasi'),
);
} else if (snapshot.hasData) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text(
'Nomor Rekening',
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 16),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
Text(
'${snapshot.data.bankName}: ',
style: const TextStyle(fontSize: 18),
),
Text(snapshot.data.accountNumber,
style: Theme.of(context)
.textTheme
.headline6
.copyWith(fontSize: 18)),
],
),
Text(snapshot.data.accountOwner,
style: Theme.of(context)
.textTheme
.headline6
.copyWith(fontSize: 18)),
],
)
],
);
}
return const Center(child: CustomCircularIndicator());
});
}
}
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:home_industry/Pages/Bank/repositories/bank_repository.dart';
import 'package:stream_transform/stream_transform.dart';
import './bloc.dart';
class BankBloc extends Bloc<BankBlocEvent, BankBlocState> {
final BankRepository _bankRepository;
BankBloc(this._bankRepository);
@override
BankBlocState get initialState => const InitialBankBlocState();
bool _hasReachedMax(BankBlocState state) =>
state is ListBankLoaded && state.hasReachedMax;
@override
Stream<BankBlocState> mapEventToState(
BankBlocEvent event,
) async* {
final currentState = state;
if ((event is FetchBank) && !_hasReachedMax(currentState)) {
try {
final banks = await _bankRepository.fetchBanks(currentState.page + 1);
if (currentState is InitialBankBlocState) {
yield ListBankLoaded(
banks.results, banks.next == null, currentState.page + 1);
return;
}
if (currentState is ListBankLoaded) {
yield ListBankLoaded(currentState.listBank + banks.results,
banks.next == null, currentState.page + 1);
return;
}
} catch (_) {
yield const ListBankError();
}
}
}
@override
Stream<Transition<BankBlocEvent, BankBlocState>> transformEvents(
Stream<BankBlocEvent> events,
TransitionFunction<BankBlocEvent, BankBlocState> transitionFn) {
return super.transformEvents(
events.debounce(
const Duration(milliseconds: 500),
),
transitionFn,
);
}
}
import 'package:equatable/equatable.dart';
abstract class BankBlocEvent extends Equatable {
const BankBlocEvent();
}
class FetchBank extends BankBlocEvent {
@override
List<Object> get props => [];
const FetchBank();
}
import 'package:equatable/equatable.dart';
import 'package:home_industry/Pages/Bank/model/bank.dart';
abstract class BankBlocState extends Equatable {
const BankBlocState(this.page);
final int page;
}
class InitialBankBlocState extends BankBlocState {
const InitialBankBlocState() : super(0);
@override
List<Object> get props => [page];
}
class ListBankLoaded extends BankBlocState {
final List<Bank> listBank;
final bool hasReachedMax;
const ListBankLoaded(this.listBank, this.hasReachedMax, page) : super(page);
@override
List<Object> get props => [listBank, hasReachedMax, page];
}
class ListBankError extends BankBlocState {
const ListBankError() : super(0);
@override
List<Object> get props => [page];
}
export 'bank_bloc_bloc.dart';
export 'bank_bloc_event.dart';
export 'bank_bloc_state.dart';
import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';
part 'bank.g.dart';
@JsonSerializable(nullable: false, fieldRename: FieldRename.snake)
class Bank extends Equatable {
final String id;
final String bankName;
final String bankAccountNumber;
final String bankAccountName;
Bank(this.id, this.bankName, this.bankAccountNumber, this.bankAccountName);
@override
List<Object> get props => [id, bankName, bankAccountNumber, bankAccountName];
factory Bank.fromJson(Map<String, dynamic> json) => _$BankFromJson(json);
Map<String, dynamic> toJson() => _$BankToJson(this);
}
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'bank.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Bank _$BankFromJson(Map<String, dynamic> json) {
return Bank(
json['id'] as String,
json['bank_name'] as String,
json['bank_account_number'] as String,
json['bank_account_name'] as String,
);
}
Map<String, dynamic> _$BankToJson(Bank instance) => <String, dynamic>{
'id': instance.id,
'bank_name': instance.bankName,
'bank_account_number': instance.bankAccountNumber,
'bank_account_name': instance.bankAccountName,
};
import 'package:equatable/equatable.dart';
import 'package:home_industry/Pages/Bank/model/bank.dart';
import 'package:json_annotation/json_annotation.dart';
part 'list_bank.g.dart';
@JsonSerializable(nullable: false, explicitToJson: true)
class ListBank extends Equatable {
final int count;
@JsonKey(nullable: true)
final String next;
@JsonKey(nullable: true)
final String previous;
final List<Bank> results;
ListBank(this.count, this.next, this.previous, this.results);
factory ListBank.fromJson(Map<String, dynamic> json) =>
_$ListBankFromJson(json);
Map<String, dynamic> toJson() => _$ListBankToJson(this);
@override
List<Object> get props => [count, next, previous, results];
}
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'list_bank.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
ListBank _$ListBankFromJson(Map<String, dynamic> json) {
return ListBank(
json['count'] as int,
json['next'] as String,
json['previous'] as String,
(json['results'] as List)
.map((e) => Bank.fromJson(e as Map<String, dynamic>))
.toList(),
);
}
Map<String, dynamic> _$ListBankToJson(ListBank instance) => <String, dynamic>{
'count': instance.count,
'next': instance.next,
'previous': instance.previous,
'results': instance.results.map((e) => e.toJson()).toList(),
};
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:home_industry/Component/custom_circular.dart';
import 'package:home_industry/Pages/Bank/bloc/bank_bloc_bloc.dart';
import 'package:home_industry/Pages/Bank/bloc/bloc.dart';
import 'package:home_industry/Pages/Bank/model/bank.dart';
import 'package:home_industry/Pages/Bank/repositories/bank_repository.dart';
import 'package:home_industry/Pages/ProductPayment/product_payment.dart';
import 'package:home_industry/State/Auth/repositories/depedencies_repositories.dart';
import 'package:provider/provider.dart';
class _RekeningBank extends StatefulWidget {
const _RekeningBank({Key key}) : super(key: key);
@override
__RekeningBankState createState() => __RekeningBankState();
}
class __RekeningBankState extends State<_RekeningBank> {
BankBloc _bankBlocBloc;
ScrollController _scrollController;
static const _scrollThreshold = 300;
void onScroll() {
final maxScroll = _scrollController.position.maxScrollExtent;
final currentScroll = _scrollController.position.pixels;
if (maxScroll - currentScroll <= _scrollThreshold) {
_bankBlocBloc.add(const FetchBank());
}
}
@override
void initState() {
_bankBlocBloc = BankBloc(BankRepository(
RepositoryProvider.of<DependenciesRepositories>(context).dio))
..add(const FetchBank());
_scrollController = ScrollController()..addListener(onScroll);
super.initState();
}
@override
void dispose() {
_bankBlocBloc.close();
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocBuilder<BankBloc, BankBlocState>(
bloc: _bankBlocBloc,
builder: (context, state) {
if (state is ListBankError) {
return const Center(
child: Text('Mohon maaf terjadi kesalahan'),
);
} else if (state is ListBankLoaded) {
return Column(
children: <Widget>[
Center(
child: Icon(Icons.arrow_drop_down),
),
Expanded(
child: ListView.builder(
controller: _scrollController,
itemCount: state.hasReachedMax
? state.listBank.length
: state.listBank.length + 1,
itemExtent: 80,
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 15),
physics: const BouncingScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return index >= state.listBank.length
? const Center(
child: CustomCircularIndicator(),
)
: _ListItemBank(
bank: state.listBank[index],
);
}),
),
],
);
}
return const Center(child: CustomCircularIndicator());
});
}
}
class _ListItemBank extends StatelessWidget {
final Bank bank;
const _ListItemBank({
Key key,
@required this.bank,
}) : assert(bank != null),
super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
border: Border.all(color: Theme.of(context).primaryColor)),
margin: const EdgeInsets.symmetric(vertical: 5),
child: Material(
type: MaterialType.card,
shadowColor: Colors.black,
borderOnForeground: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(4.0))),
elevation: 1,
child: Center(
child: ListTile(
onTap: () {
context.read<SelectedBank>().selectBank = bank;
Navigator.of(context).pop();
},
title: Text(
bank.bankName,
style: Theme.of(context).textTheme.headline6,
),
trailing: context.watch<SelectedBank>().selectedBank?.id == bank.id
? Icon(Icons.check)
: Icon(Icons.navigate_next),
),
),
),
);
}
}
class Rekening extends StatelessWidget {
const Rekening();
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
const Text(
'Bank tujuan',
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 16),
),
context.watch<SelectedBank>().selectedBank == null
? Text(
'Silahkan pilih bank tujuan',
style: Theme.of(context).textTheme.headline6,
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
Text(
'${context.watch<SelectedBank>().selectedBank.bankName}: ',
style: const TextStyle(fontSize: 18),
),
Text(
context
.watch<SelectedBank>()
.selectedBank
.bankAccountNumber,
style: Theme.of(context)
.textTheme
.headline6
.copyWith(fontSize: 18)),
],
),
Text(
'Atas nama: '
'${context.watch<SelectedBank>().selectedBank.bankAccountName}',
style: Theme.of(context)
.textTheme
.headline6
.copyWith(fontSize: 18)),
],
),
OutlineButton.icon(
onPressed: () {
FocusScope.of(context).unfocus();
final selectedBank =
Provider.of<SelectedBank>(context, listen: false);
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return ChangeNotifierProvider.value(
value: selectedBank,
child: FractionallySizedBox(
heightFactor: 0.5, child: const _RekeningBank()),
);
},
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius:
BorderRadius.vertical(top: Radius.circular(25))),
);
},
borderSide:
BorderSide(color: Theme.of(context).primaryColor, width: 2),
icon: Icon(Icons.payment),
label: Text('Pilih bank tujuan'))
],
);
}
}
import 'package:dio/dio.dart';
import 'package:home_industry/Pages/Bank/model/list_bank.dart';
class BankRepository {
static const url = '/bank-account-transfer-destinations/';
static const pageSize = 10;
final Dio _dio;
const BankRepository(this._dio);
Future<ListBank> fetchBanks(int pageNumber) async {
final response = await _dio
.get(url, queryParameters: {'page': pageNumber, 'page_size': pageSize});
return ListBank.fromJson(response.data);
}
}
......@@ -397,24 +397,6 @@ class _ModalCartItem extends StatelessWidget {
],
),
),
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text(
'Deskripsi',
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.w800),
),
Text(
'${cartItem.product.description}',
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 18),
),
],
),
),
],
),
),
......
......@@ -8,10 +8,11 @@ import 'package:home_industry/Component/blue_button.dart';
import 'package:home_industry/Component/border_blue_button.dart';
import 'package:home_industry/Component/custom_input_form.dart';
import 'package:home_industry/Component/product_image.dart';
import 'package:home_industry/Component/rekening.dart';
import 'package:home_industry/Pages/Bank/rekening.dart';
import 'package:home_industry/Pages/Donation/bloc_donation/bloc.dart';
import 'package:home_industry/Pages/Donation/repositories/donation_repository.dart';
import 'package:home_industry/Pages/DonationHistory/model/donation.dart';
import 'package:home_industry/Pages/ProductPayment/product_payment.dart';
import 'package:home_industry/Pages/Program/model/program.dart';
import 'package:home_industry/State/Auth/repositories/depedencies_repositories.dart';
import 'package:home_industry/State/ChangeBottomNavigatonBar/bloc.dart';
......@@ -107,8 +108,13 @@ class DonasiBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Provider<Donation>.value(
value: donation,
return MultiProvider(
providers: [
Provider<Donation>.value(value: donation),
ChangeNotifierProvider<SelectedBank>(
create: (_) => SelectedBank(),
)
],
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
......
......@@ -21,8 +21,18 @@ class Donation {
final String readableDonationStatus;
@JsonKey(nullable: true)
final String proofOfBankTransfer;
@JsonKey(nullable: true)
final String userBankAccountName;
final String userBankAccountNumber;
@JsonKey(nullable: true)
final String userBankName;
@JsonKey(nullable: true)
final String transferDestinationBankName;
@JsonKey(nullable: true)
final String transferDestinationBankAccountName;
@JsonKey(nullable: true)
final String transferDestinationBankAccountNumber;
final DateTime createdAt;
final DateTime updatedAt;
......@@ -32,6 +42,10 @@ class Donation {
this.user,
this.userUsername,
this.program,
this.userBankName,
this.transferDestinationBankName,
this.transferDestinationBankAccountName,
this.transferDestinationBankAccountNumber,
this.programCode,
this.userFullName,
this.userPhoneNumber,
......@@ -41,7 +55,6 @@ class Donation {
this.readableDonationStatus,
this.proofOfBankTransfer,
this.userBankAccountName,
this.userBankAccountNumber,
this.createdAt,
this.updatedAt});
......
......@@ -13,6 +13,13 @@ Donation _$DonationFromJson(Map<String, dynamic> json) {
user: json['user'] as String,
userUsername: json['user_username'] as String,
program: json['program'] as String,