-
Notifications
You must be signed in to change notification settings - Fork 213
Description
I use Redux to handle my globalstate, and BloC as localstate. I need to store my globalmodel in Redux to my BloC model on Redux onInit. I call BloC event in Redux onInit to get my BloC model same as globalmodel. But, I got my Redux model change even if I dont callback Redux update model methode when my BloC doing update model. But if I didn't call BloC event in Redux onInit, the model keep flow well. How I can handle this, so that my globalmodel didn't change when I update my BloC model?
this is my code:
import 'dart:async';
import 'package:kmb/redux/actions.dart';
import 'package:kmb/redux/global-model.dart';
import 'package:kmb/src/models/model-account.dart';
import 'package:kmb/src/views/settings-page/place-page/controller/place-bloc.dart';
import 'package:kmb/src/views/settings-page/place-page/signup-map-dialog.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class PlaceParent extends StatelessWidget {
@OverRide
Widget build(BuildContext context) {
return BlocProvider(
create: (context)=>PlaceBloc(),
child: PlacePage(),
);
}
}
class PlacePage extends StatefulWidget {
@OverRide
_PlacePageState createState() => _PlacePageState();
}
class _PlacePageState extends State {
TextEditingController addressCntrl = new TextEditingController();
Completer _controller = Completer();
final GlobalKey _scaffoldKey = new GlobalKey();
GlobalModel informasi;
PlaceBloc provider;
Set _marker = {};
GoogleMapController mapController;
@OverRide
void initState() {
super.initState();
informasi = GlobalModel.initState();
provider = BlocProvider.of(context);
}
@OverRide
void dispose() {
provider.close();
super.dispose();
}
@OverRide
Widget build(BuildContext context) {
return StoreConnector<GlobalModel,OnStoringInformationUpdatePointCallback>(
key: Key('StoreLocation'),
converter: (store)=>(informasiGlobal)=>(){
store.dispatch(ActionStoringInformation(informasi));
},
onInit: (stored){
print(stored.state.accountInfo.toMap());
informasi = stored.state;
provider.add(PlaceBlocEventStoreInit(informasi.accountInfo));
addressCntrl.text = stored.state.accountInfo.address;
},
onWillChange: (prevstate, nextstate){
print('prevs: $prevstate');
print('prevs: $nextstate');
},
builder: (context, callback){
return BlocListener<PlaceBloc, PlaceBlocModel>(
bloc: BlocProvider.of(context),
listener: (context, state){
if(!state.updateOnProccess){
if(state.updateOnFinish){
print('Masuk Sini CUK');
informasi.accountInfo.updatePoint(state.account);
callback(informasi);
Navigator.of(context).pop();
provider.add(PlaceBlocEventNormalize());
}
}
if(!state.updateLocOnProccess){
if(state.updateLocOnFinish){
addressCntrl.text = state.account.address;
mapController.animateCamera(CameraUpdate.newCameraPosition(CameraPosition(
target: LatLng(state.account.pointLat, state.account.pointLon),
zoom: 16.0
)));
_marker.clear();
_marker.add(Marker(
markerId: MarkerId('001'),
position: LatLng(state.account.pointLat, state.account.pointLon)
));
provider.add(PlaceBlocEventNormalize());
}
}
},
child: BlocBuilder<PlaceBloc, PlaceBlocModel>(
builder: (context, state){
return Scaffold(
key: _scaffoldKey,
body: Container(
decoration: BoxDecoration(
color: Colors.white
),
child: Padding(
padding: const EdgeInsets.only(left:20.0, right:20.0),
child: ListView(
children: [
Divider(
color: Colors.transparent,
height: 30.0,
),
Row(
children: [
InkWell(
child: Icon(Icons.close),
onTap: (){
Navigator.of(context).pop();
},
),
VerticalDivider(
color: Colors.transparent,
width: 10.0,
),
Text('place Point', style: TextStyle(fontSize: 24.0),)
],
),
Divider(
color: Colors.transparent,
height: 20.0,
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(5.0),
bottomRight: Radius.circular(5.0),
),
),
child: Column(
children: [
Container(
height: 200.0,
child: GoogleMap(
mapType: MapType.normal,
initialCameraPosition: CameraPosition(
target: LatLng(-6.1753924, 106.8249641),
zoom: 16.0
),
onMapCreated: (controller){
mapController = controller;
// if(state.account.pointLat!=null && state.account.pointLon!=null){
// mapController.animateCamera(CameraUpdate.newCameraPosition(CameraPosition(
// target: LatLng(state.account.pointLat, state.account.pointLon),
// zoom: 16.0
// )));
// _marker.add(Marker(
// markerId: MarkerId('001'),
// position: LatLng(state.account.pointLat, state.account.pointLon)
// ));
// }
_controller.complete(controller);
},
markers: _marker,
),
),
Container(
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(5.0),
bottomRight: Radius.circular(5.0),
),
),
child: Padding(
padding: const EdgeInsets.fromLTRB(16.0,10.0,16.0,10.0),
child: Container(
child: InkWell(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.launch, color: Colors.white, size: 32.0,),
VerticalDivider(
color: Colors.transparent,
width: 10.0,
),
Text('Open Map', style: TextStyle(color: Colors.white, fontSize: 16.0, fontWeight: FontWeight.w600),)
],
),
onTap: (){
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context){
print(state.account.pointLon);
return state.account.pointLon!=null? SignUpMapDialog(
currPositionLat: state.account.pointLat,
currPositionLon: state.account.pointLon,
onItemChoosed: (locparam){
provider.add(PlaceBlocEventStoreUpdateOnProcess());
provider.add(PlaceBlocEventStoreUpdate(Account(pointLat: locparam.pointLoc.latitude, pointLon: locparam.pointLoc.longitude, address: locparam.address)));
},
):SignUpMapDialog(
currPositionLat: -6.1753924,
currPositionLon: 106.8249641,
onItemChoosed: (locparam){
provider.add(PlaceBlocEventStoreUpdateOnProcess());
provider.add(PlaceBlocEventStoreUpdate(Account(pointLat: locparam.pointLoc.latitude, pointLon: locparam.pointLoc.longitude, address: locparam.address)));
},
);
}
);
},
),
),
),
)
],
),
),
Divider(
color: Colors.transparent,
height: 30.0,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Latitude', style: TextStyle(fontWeight: FontWeight.w600,fontSize: 16.0),),
Divider(height: 4.0, color: Colors.transparent,),
Text('${state.account.pointLat}', style: TextStyle(fontSize: 14.0, color: Colors.grey),),
],
),
Padding(
padding: const EdgeInsets.only(top:10.0, bottom:10.0),
child: Divider(height: 1.0, color: Colors.grey,),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Longitude', style: TextStyle(fontWeight: FontWeight.w600,fontSize: 16.0),),
Divider(height: 4.0, color: Colors.transparent,),
Text('${state.account.pointLon}', style: TextStyle(fontSize: 14.0, color: Colors.grey),),
],
),
Padding(
padding: const EdgeInsets.only(top:10.0, bottom:10.0),
child: Divider(height: 1.0, color: Colors.grey,),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Address', style: TextStyle(fontWeight: FontWeight.w600,fontSize: 16.0),),
Container(
child: TextFormField(
decoration: InputDecoration(
hintText: "Address",
),
controller: addressCntrl,
),
),
],
),
Divider(
color: Colors.transparent,
height: 30.0,
),
InkWell(
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.all(Radius.circular(5.0))
),
child: Padding(
padding: const EdgeInsets.fromLTRB(10.0,14.0,10.0,14.0),
child: Center(child: Text('Confirm', style: TextStyle(fontSize: 18.0, color: Colors.white, fontWeight: FontWeight.w700),)),
)
),
onTap: (){
provider.add(PlaceBlocEventUpdateRemoteOnProcess());
provider.add(PlaceBlocEventUpdateRemote(state.account));
},
),
Divider(
color: Colors.transparent,
height: 30.0,
),
],
),
),
),
);
}
)
);
}
);
}
}
typedef OnStoringInformationUpdatePointCallback = Function(GlobalModel informasiGlobal);
my Bloc code:
import 'dart:convert';
import 'package:bloc/bloc.dart';
import 'package:kmb/src/models/model-account.dart';
import 'package:kmb/src/services/api-serv.dart';
import 'package:equatable/equatable.dart';
import 'package:kmb/src/globals.dart' as globals;
import 'package:http/http.dart';
class PlaceBlocModel{
Account account;
bool onInit;
bool updateOnProccess;
bool updateOnFinish;
bool updateLocOnProccess;
bool updateLocOnFinish;
PlaceBlocModel({
this.account,
this.onInit,
this.updateOnProccess,
this.updateOnFinish,
this.updateLocOnFinish,
this.updateLocOnProccess
});
PlaceBlocModel.initState(){
this.account = Account.initState();
this.onInit = true;
this.updateOnProccess = false;
this.updateOnFinish = false;
this.updateLocOnProccess = false;
this.updateLocOnFinish = false;
}
void fromMapUpdate(Map<String, dynamic> map){
this.account.pointLat = map['data']['point_lat'];
this.account.pointLon = map['data']['point_lon'];
this.account.address = map['data']['address'];
this.account.token = map['token'];
}
void locUpdate(Account accountMap){
this.account.pointLat = accountMap.pointLat;
this.account.pointLon = accountMap.pointLon;
this.account.address = accountMap.address;
}
PlaceBlocModel.copy(PlaceBlocModel state){
this.account = state.account;
this.onInit = state.onInit;
this.updateOnProccess = state.updateOnProccess;
this.updateOnFinish = state.updateOnFinish;
this.updateLocOnProccess = state.updateLocOnProccess;
this.updateLocOnFinish = state.updateLocOnFinish;
}
}
abstract class PlaceBlocEvent extends Equatable{
@OverRide
List get props => [];
}
class PlaceBlocEventStoreInit extends PlaceBlocEvent{
final Account account;
PlaceBlocEventStoreInit(this.account);
}
class PlaceBlocEventStoreUpdate extends PlaceBlocEvent{
final Account account;
PlaceBlocEventStoreUpdate(this.account);
}
class PlaceBlocEventStoreUpdateOnProcess extends PlaceBlocEvent{}
class PlaceBlocEventUpdateRemoteOnProcess extends PlaceBlocEvent{}
class PlaceBlocEventUpdateRemote extends PlaceBlocEvent{
final Account account;
PlaceBlocEventUpdateRemote(this.account);
}
class PlaceBlocEventNormalize extends PlaceBlocEvent{}
class PlaceBloc extends Bloc<PlaceBlocEvent, PlaceBlocModel>{
@OverRide
PlaceBlocModel get initialState => PlaceBlocModel.initState();
@OverRide
Stream mapEventToState(PlaceBlocEvent event)async* {
if(event is PlaceBlocEventUpdateRemote){
print(event.account.toMapPlacePoint());
PlaceBlocModel retval = await PlacePointUpdate(event.account.toMapPlacePoint(), state);
yield retval;
}else if(event is PlaceBlocEventStoreInit){
if(state.onInit){
yield PlaceBlocModel(account: event.account, onInit: false, updateOnFinish: false, updateOnProccess: false, updateLocOnFinish: false, updateLocOnProccess: false);
}
}else if(event is PlaceBlocEventUpdateRemoteOnProcess){
yield PlaceBlocModel(account: state.account, onInit: false, updateOnFinish: false, updateOnProccess: true, updateLocOnFinish: state.updateLocOnFinish, updateLocOnProccess: state.updateLocOnProccess);
}else if(event is PlaceBlocEventStoreUpdateOnProcess){
yield PlaceBlocModel(account: state.account, onInit: false, updateOnFinish: state.updateOnFinish, updateOnProccess: state.updateOnProccess, updateLocOnFinish: false, updateLocOnProccess: true);
}else if(event is PlaceBlocEventStoreUpdate){
PlaceBlocModel currState = PlaceBlocModel.copy(state);
currState.locUpdate(event.account);
currState.updateLocOnFinish = true;
currState.updateLocOnProccess = false;
yield currState;
}else if(event is PlaceBlocEventNormalize){
yield PlaceBlocModel(account: state.account, onInit: false, updateOnFinish: false, updateOnProccess: false, updateLocOnFinish: false, updateLocOnProccess: false);
}
}
Future PlacePointUpdate(Map<String, dynamic> map, PlaceBlocModel state)async{
final Response response = await callApi(APIMethode.POST, globals.urlUpdatePlacePoint(), data: map);
if(response.statusCode == 200){
final jsonRes = json.decode(response.body);
if(jsonRes['error']==true){
return PlaceBlocModel(account: state.account, updateOnFinish: true, updateOnProccess: false);
}else{
print(map);
PlaceBlocModel Place = PlaceBlocModel.copy(state)..fromMapUpdate(jsonRes);
Place.updateOnFinish = true;
Place.updateOnProccess = false;
return Place;
}
}else{
return PlaceBlocModel(account: state.account, updateOnFinish: true, updateOnProccess: false);
}
}
}