the dart code below displays a web pdf by authenticating with a token to a backend via the webviewx pub: , the token however on android is not passed and the page displays an error of authentication, what should I change to ensure that the token is also passed on android? How to solve this error by WebViewX?
Dart Code:
import 'dart:developer';
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:webviewx/webviewx.dart';
class WebViewXPage extends StatefulWidget {
final Url, Token;
WebViewXPage(this.Url, this.Token);
#override
_WebViewXPageState createState() => _WebViewXPageState();
}
class _WebViewXPageState extends State<WebViewXPage> {
late WebViewXController webviewController;
final initialContent =
'<h4> This is some hardcoded HTML code embedded inside the webview <h4> <h2> Hello world! <h2>';
final executeJsErrorMessage =
'Failed to execute this task because the current content is (probably) URL that allows iframe embedding, on Web.\n\n'
'A short reason for this is that, when a normal URL is embedded in the iframe, you do not actually own that content so you cant call your custom functions\n'
'(read the documentation to find out why).';
Size get screenSize => MediaQuery.of(context).size;
#override
void dispose() {
webviewController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
padding: const EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
Container(
decoration: BoxDecoration(
border: Border.all(width: 0.2),
),
child: _buildWebViewX(),
),
],
),
),
),
);
}
Widget _buildWebViewX() {
return WebViewX(
key: const ValueKey('webviewx'),
initialContent: widget.Url,
initialSourceType: SourceType.html,
height: screenSize.height - 150,
width: screenSize.width,
onWebViewCreated: (controller) =>{ webviewController = controller, _setUrl()},
onPageFinished: (src) => debugPrint('The page has finished loading: $src\n'),
jsContent: const {
EmbeddedJsContent(
js: "function testPlatformIndependentMethod() { console.log('Hi from JS') }",
),
EmbeddedJsContent(
webJs: "function testPlatformSpecificMethod(msg) { TestDartCallback('Web callback says: ' + msg) }",
mobileJs:
"function testPlatformSpecificMethod(msg) { TestDartCallback.postMessage('Mobile callback says: ' + msg) }",
),
},
webSpecificParams: const WebSpecificParams(
printDebugInfo: true,
),
mobileSpecificParams: const MobileSpecificParams(
androidEnableHybridComposition: true,
),
navigationDelegate: (navigation) {
debugPrint(navigation.content.sourceType.toString());
return NavigationDecision.navigate;
},
);
}
void _setUrl() {
webviewController.loadContent(widget.Url, SourceType.urlBypass, headers: {'Cmdbuild-authorization': widget.Token});
}
Widget buildSpace({
Axis direction = Axis.horizontal,
double amount = 0.2,
bool flex = true,
}) {
return flex
? Flexible(
child: FractionallySizedBox(
widthFactor: direction == Axis.horizontal ? amount : null,
heightFactor: direction == Axis.vertical ? amount : null,
),
)
: SizedBox(
width: direction == Axis.horizontal ? amount : null,
height: direction == Axis.vertical ? amount : null,
);
}
}
Related
I'm struggling second day on this issue.
I use flutter google map to show about hundred custom markers with network image icons, that can be svg or png (using MarkerGenerator).
After opening the map page, MapCubit start to load items from API. In build i have BlocConsumer, where is listener, that build markers when loaded in that cubit and builder that build GoogleMap.
Problem is, that on first opening of page there are no images in markers, only white circle. When I tried to set one image url to all markers, it was loaded properly. Then, when i go on previous page or hot reload (not always), icons are there. On same page i have legend, that draw images from same urls, where images are set properly in most times. Sometimes it is need to go back and forward more times.
I can load icons after click on item in filter, that calls MapCubit, too.
I dont know, if it means something, but next problem, what i have is, that on release and appbundle build, no map is shown, only grey screen, buttons on side and google logo on bottom left.
I tried many tips on internet, but nothing helped.
Preview of first opening of MapPage
Preview of filter at first opening (has all icons)
Preview of second opening of MapPage
Preview of third opening of MapPage (has all icons)
MapPage (MarkerGenerator is in listener and initState becouse of two different uses that needs it)
class _MapAreaState extends State<MapArea> {
MapCubit _mapCubit;
Set<Marker> markers = {};
List<CustomMarker> markerWidgets = [];
bool markersLoaded = false;
#override
void initState() {
_mapCubit = BlocProvider.of<MapCubit>(context);
markers = {};
MarkerGenerator(
_mapCubit.state.items.map((e) => CustomMarker(type: e.type)).toList(),
(bitmaps) {
setState(() {
bitmaps.asMap().forEach((mid, bmp) {
IMapItem item = _mapCubit.state.items[mid];
markers.add(Marker(
markerId: MarkerId(item.title),
position: item.latLng,
icon: BitmapDescriptor.fromBytes(bmp),
// markerId: MarkerId(item.title),
// position: item.latLng,
onTap: () async {
await _mapCubit.showDetail(item);
}));
});
});
}).generate(context);
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
color: tercialBackgroundColor,
child: BlocConsumer<MapCubit, MapState>(
bloc: _mapCubit,
listener: (context, state) {
if (state.changedItems && state.items.isNotEmpty) {
markerWidgets = _mapCubit.state.items
.map((e) => CustomMarker(type: e.type))
.toList();
markers = {};
MarkerGenerator(markerWidgets, (bitmaps) {
setState(() {
bitmaps.asMap().forEach((mid, bmp) {
log(bmp.toString());
IMapItem item = _mapCubit.state.items[mid];
markers.add(Marker(
markerId: MarkerId(item.title),
position: item.latLng,
icon: BitmapDescriptor.fromBytes(bmp),
// markerId: MarkerId(item.title),
// position: item.latLng,
onTap: () async {
await _mapCubit.showDetail(item);
}));
});
});
}).generate(context);
}
},
builder: (context, state) {
return Stack(
children: [
GoogleMap(
zoomControlsEnabled: false,
compassEnabled: false,
markers: markers,
// markers: Set<Marker>.of(state.markers),
initialCameraPosition: CameraPosition(
target: state.items.length == 1
? state.items[0].latLng
: LatLng(49.07389317899512, 19.30980263713778),
zoom: 8.5,
),
minMaxZoomPreference: MinMaxZoomPreference(8, 22),
cameraTargetBounds: CameraTargetBounds(LatLngBounds(
northeast: LatLng(50.16477808289659, 20.56397637952818),
southwest: LatLng(48.75267922516721, 18.76330228064009),
)),
onMapCreated: (GoogleMapController controller) {
if (!_mapCubit.controller.isCompleted) {
rootBundle
.loadString('assets/googleMapsStyle.json')
.then((string) async {
controller.setMapStyle(string);
});
_mapCubit.controller.complete(controller);
log(_mapCubit.controller.toString());
log(controller.toString());
setState(() {
});
}
},
),
// if(state.items.isEmpty)
// FullScreenLoadingSpinner()
],
);
},
),
);
}
}
CustomMarker class
class CustomMarker extends StatelessWidget {
final ItemType type;
const CustomMarker({Key key, this.type}) : super(key: key);
#override
Widget build(BuildContext context) {
// precachePicture(
// svgPicture.pictureProvider,
// Get.context!,
// );
// if(type.icon is /-
return Stack(
clipBehavior: Clip.none,
children: [
Icon(
Icons.add_location,
color: type.color,
size: 56,
),
Positioned(
left: 16,
top: 10,
child: Container(
width: 24,
height: 24,
decoration: BoxDecoration(
color: primaryBackgroundColor,
borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.all(1.0),
child: Center(child: type.icon),
),
),
),
],
);
}
}
Icon setting in ItemType factory, that is used in CustomMarker
icon: map['icon'] != null
? (map['icon'] is Image
? map['icon']
: (map['icon'].substring(map['icon'].length - 4) == '.svg'
? WebsafeSvg.network(
map['icon'],
width: 18,
height: 18,
color: Colors.black,
placeholderBuilder: (BuildContext context) => Container(
padding: const EdgeInsets.all(30.0),
child: const CircularProgressIndicator()),
)
: Image.network(map['icon'])))
Lately somewhen this exception is in console
======== Exception caught by image resource service =====================
The following HttpException was thrown resolving an image codec:
, uri = https://www.xxx.sk/images/svgs/culture.png
When the exception was thrown, this was the stack:
Image provider: NetworkImage("https://www.xxx.sk/images/svgs/culture.png", scale: 1.0)
Image key: NetworkImage("https://www.xxx.sk/images/svgs/culture.png", scale: 1.0)
I dont know, what all to send, so far at least this. Thanks.
I try to rebuild instagram stories by using GetX. I always receive this issue.
Can anyone help me solve this problem?
ScrollController attached to multiple scroll views.
'package:flutter/src/widgets/scroll_controller.dart':
Failed assertion: line 109 pos 12: '_positions.length == 1'
I try to rebuild instagram stories by using GetX. I always receive this issue.
Can anyone help me solve this problem?
ScrollController attached to multiple scroll views.
'package:flutter/src/widgets/scroll_controller.dart':
Failed assertion: line 109 pos 12: '_positions.length == 1'
import 'package:flamingo/Business_Logic/GetXControllers/Pages_Controllers/Stories_Controller.dart';
import 'package:flamingo/Data/DataProviders/StoriesList.dart';
import 'package:flamingo/Data/Models/All_Models.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class Stories extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetBuilder<StoriesController>(
init: StoriesController(),
builder: (storiesCtrl) {
return Scaffold(
backgroundColor: Colors.black,
body: GestureDetector(
onTapDown: (details) => storiesCtrl.onTapDown(
details, story[storiesCtrl.currentIndex.value]),
child: Stack(
children: <Widget>[
PageView.builder(
controller: storiesCtrl.pageC,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, i) {
final StoryModel s = story[i];
switch (s.media) {
case MediaType.image:
return Image.network(
s.image,
fit: BoxFit.cover,
);
}
return const SizedBox.shrink();
},
),
Positioned(
top: 15.0,
left: 10.0,
right: 10.0,
child: Row(
children: story
.asMap()
.map((i, e) {
return MapEntry(
i,
Flexible(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 1.5),
child: LayoutBuilder(
builder: (context, constraints) {
return Stack(
children: <Widget>[
_buildContainer(
double.infinity,
i < storiesCtrl.currentIndex.value
? Colors.white
: Colors.white.withOpacity(0.5),
),
i == storiesCtrl.currentIndex.value
? AnimatedBuilder(
animation: storiesCtrl.animC,
builder: (context, child) {
return _buildContainer(
constraints.maxWidth *
storiesCtrl.animC.value,
Colors.white,
);
},
)
: const SizedBox.shrink(),
],
);
}),
),
));
})
.values
.toList(),
),
),
],
),
),
);
},
);
}
Container _buildContainer(double width, Color color) {
return Container(
height: 5.0,
width: width,
decoration: BoxDecoration(
color: color,
border: Border.all(
color: Colors.black26,
width: 0.8,
),
borderRadius: BorderRadius.circular(3.0),
),
);
}
}
import 'package:flamingo/Data/Models/StoryModel.dart';
import 'package:flamingo/Utils/AllUtils.dart';
import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';
import 'package:flamingo/Data/DataProviders/StoriesList.dart';
import 'package:get/get.dart';
class StoriesController extends GetxController
with SingleGetTickerProviderMixin {
List<StoryModel> stories;
AnimationController animC;
var pageC;
var currentIndex = 0.obs;
#override
void onInit() {
stories = story;
super.onInit();
pageC = PageController();
animC = AnimationController(vsync: this);
final StoryModel firstStory = stories.first;
loadStory(story: firstStory, animateToPage: false);
animC.addStatusListener((status) {
if (status == AnimationStatus.completed) {
animC.stop();
animC.reset();
if (currentIndex.value + 1 < stories.length) {
currentIndex.value += 1;
loadStory(story: stories[currentIndex.value]);
update();
} else {
currentIndex.value = 0;
loadStory(story: stories[currentIndex.value]);
update();
}
}
});
}
void onTapDown(TapDownDetails details, StoryModel s) {
final double dx = details.globalPosition.dx;
if (dx < GlobalSize.screenWidth / 3) {
if (currentIndex.value - 1 >= 0) {
currentIndex.value -= 1;
loadStory(story: story[currentIndex.value]);
update();
}
} else if (dx > 2 * GlobalSize.screenWidth / 3) {
if (currentIndex.value + 1 < story.length) {
currentIndex.value += 1;
loadStory(story: story[currentIndex.value]);
} else {
currentIndex.value = 0;
loadStory(story: story[currentIndex.value]);
}
}
}
void loadStory({StoryModel story, bool animateToPage = true}) {
animC.stop();
animC.reset();
switch (story.media) {
case MediaType.image:
animC.duration = story.duration;
animC.forward();
break;
}
if (animateToPage) {
pageC.animateToPage(
currentIndex.value,
duration: const Duration(microseconds: 1),
curve: Curves.easeInOut,
);
}
}
#override
void onClose() {
pageC.value.dispose();
animC.dispose();
super.onClose();
}
}
Okay so I had this same issue but for me it was not actually related to the code where I used my controller. Typically this issue shows up if you access the same controller from multiple pages. However, it also occurs if you have multiple instances of the same page on the router stack. In my case I was using Get.to() elsewhere in my application to navigate back to my home page which created another instance of my home page on the stack, hence the multiple controllers error.
So to solve it, I changed Get.to() to Get.offAll(). If you are using named routes, switch Get.toNamed() to Get.offAllNamed().
If you get errors after doing this that say your controllers are no longer found, in your bindings, set permanent: true when using Get.put() to instantiate your controller: Get.put(Home(), permanent: true);
Looking at your code, it does not look like the error is coming from using the same controller twice and may instead occur when you route back to this page from somewhere in your application. Took me forever to figure out but essentially Flutter makes another instance of the "shared" controller when you add the same page onto the stack so you have to remove the original page from the stack when navigating.
If anyone gets this error from navigating and is not using GetX for state management, use Navigation.pushNamedAndRemoveUntil() to navigate back to the page with the controller.
i'm trying to come up with best way to draw a floor plan in flutter, something like these images, but it would be for regals in one concrete shop, instead of plan of shopping centre with multiple shops.
floor plan 1
floor plan 2
i decided rectangles would be sufficient enough for now and i have multiple ideas on how to execute, but no idea which one is the best. or maybe there is even better one i have not thought of
1. using custom painter
regals have attributes: ax, ay, bx, by, so they go from point a (left bottom) to b (right upper)
code like this
final rect = Rect.fromPoints(
Offset(regal.ax.toDouble(), size.height - regal.ay.toDouble()),
Offset(regal.bx.toDouble(), size.height - regal.by.toDouble()),
);
this is good because it is flexible, there is pretty much unlimited range of options, but using CustomPainter is a bit buggy in my case, alongside with Transform and GestureDetector it bugs out sometimes and instead of clicking on "buttons" you need to track where user clicked, ehm, tapped.
2. using gridView?
i dont have thought this thru as much as first option, but big plus would be using styled buttons as regals, instead of rectangles.
possible problems would be button sizing, if one regal would be times bigger than others.
regal attributes would be order on x axis, order on y axis, x flex (for example 3 as 3 times of base size), y flex
i think i have not thought of the best solution yet.
what would it be?
Here is a quick playground using a Stack of Regals who are just Containers in this quick implementation under 250 lines of code.
Click the FloatActionButton to create random Regal. Then, you can define the position of each Regal and its Size, within the limit of the Floor Plan and Max/min Regal Size.
In this quick implementation, the position of a Regal can be defined both with Gestures or Sliders; while its size can only be defined using the sliders.
Package Dependencies
Riverpod (Flutter Hooks flavor) for State Management
Freezed for Domain classes immutability
Full Source Code (222 lines)
import 'dart:math' show Random;
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
part '66478145.floor_plan.freezed.dart';
void main() {
runApp(
ProviderScope(
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: HomePage(),
),
),
);
}
class HomePage extends HookWidget {
#override
Widget build(BuildContext context) {
final regals = useProvider(regalsProvider.state);
return Scaffold(
body: Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Stack(
children: [
Container(
width: kFloorSize.width,
height: kFloorSize.height,
color: Colors.amber.shade100),
...regals
.map(
(regal) => Positioned(
top: regal.offset.dy,
left: regal.offset.dx,
child: GestureDetector(
child: RegalWidget(regal: regal),
),
),
)
.toList(),
],
),
const SizedBox(width: 16.0),
RegalProperties(),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read(regalsProvider).createRegal(),
child: Icon(Icons.add),
),
);
}
}
class RegalWidget extends HookWidget {
final Regal regal;
const RegalWidget({Key key, this.regal}) : super(key: key);
#override
Widget build(BuildContext context) {
final _previousOffset = useState<Offset>(null);
final _refOffset = useState<Offset>(null);
return GestureDetector(
onTap: () => context.read(selectedRegalIdProvider).state = regal.id,
onPanStart: (details) {
_previousOffset.value = regal.offset;
_refOffset.value = details.localPosition;
},
onPanUpdate: (details) => context.read(regalsProvider).updateRegal(
regal.copyWith(
offset: _previousOffset.value +
details.localPosition -
_refOffset.value),
),
child: Container(
width: regal.size.width,
height: regal.size.height,
color: regal.color,
),
);
}
}
class RegalProperties extends HookWidget {
#override
Widget build(BuildContext context) {
final regal = useProvider(selectedRegalProvider);
return Padding(
padding: EdgeInsets.all(16.0),
child: regal == null
? Text('Click a Regal to start')
: Form(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('WIDTH'),
Slider(
min: kRegalMinSize.width,
max: kRegalMaxSize.width,
value: regal.size.width,
onChanged: (value) => context
.read(regalsProvider)
.updateRegal(
regal.copyWith(size: Size(value, regal.size.height)),
),
),
const SizedBox(height: 16.0),
Text('HEIGHT'),
Slider(
min: kRegalMinSize.height,
max: kRegalMaxSize.height,
value: regal.size.height,
onChanged: (value) => context
.read(regalsProvider)
.updateRegal(
regal.copyWith(size: Size(regal.size.width, value)),
),
),
const SizedBox(height: 16.0),
Text('LEFT'),
Slider(
min: 0,
max: kFloorSize.width - regal.size.width,
value: regal.offset.dx,
onChanged: (value) =>
context.read(regalsProvider).updateRegal(
regal.copyWith(
offset: Offset(value, regal.offset.dy)),
),
),
const SizedBox(height: 16.0),
Text('TOP'),
Slider(
min: 0,
max: kFloorSize.height - regal.size.height,
value: regal.offset.dy,
onChanged: (value) =>
context.read(regalsProvider).updateRegal(
regal.copyWith(
offset: Offset(regal.offset.dx, value)),
),
),
],
),
),
);
}
}
final selectedRegalIdProvider = StateProvider<String>((ref) => null);
final selectedRegalProvider = Provider<Regal>((ref) {
final selectedId = ref.watch(selectedRegalIdProvider).state;
final regals = ref.watch(regalsProvider.state);
return regals.firstWhereOrNull((regal) => regal.id == selectedId);
});
final regalsProvider =
StateNotifierProvider<RegalsNotifier>((ref) => RegalsNotifier());
class RegalsNotifier extends StateNotifier<List<Regal>> {
final Size floorSize;
final Size maxSize;
RegalsNotifier({
this.floorSize = const Size(600, 400),
this.maxSize = const Size(100, 100),
List<Regal> state,
}) : super(state ?? []);
void createRegal() {
state = [...state, Regal.random];
print(state.last);
}
void updateRegal(Regal updated) {
state = state.map((r) => r.id == updated.id ? updated : r).toList();
}
}
#freezed
abstract class Regal implements _$Regal {
const factory Regal({
String id,
Color color,
Offset offset,
Size size,
}) = _Regal;
static Regal get random {
final rnd = Random();
return Regal(
id: DateTime.now().millisecondsSinceEpoch.toString(),
color: Color(0xff555555 + rnd.nextInt(0x777777)),
offset: Offset(
rnd.nextDouble() * (kFloorSize.width - kRegalMaxSize.width),
rnd.nextDouble() * (kFloorSize.height - kRegalMaxSize.height),
),
size: Size(
kRegalMinSize.width +
rnd.nextDouble() * (kRegalMaxSize.width - kRegalMinSize.width),
kRegalMinSize.height +
rnd.nextDouble() * (kRegalMaxSize.height - kRegalMinSize.height),
),
);
}
}
// CONFIG
const kFloorSize = Size(600, 400);
const kRegalMinSize = Size(10, 10);
const kRegalMaxSize = Size(200, 200);
The Problem
I am building a basic app in Flutter that gets the user's location and displays nearby places in a swipe-card format similar to Tinder. I managed to implement geolocation however when using FutureProvider/Consumer I'm experiencing a weird bug where the user's relative distance to the place is overwritten with the first distance value in the card deck. Although I am new to flutter and the Provider package, I believe there is a simple fix to this.
Side note: After searching around on Google, I attempted to use FutureProvider.value() to prevent the old value from updating but had no luck.
Thank you in advance for any assistance or direction!
A Quick Demo
Packages Used
card_swipe.dart
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:provider/provider.dart';
import 'package:swipe_stack/swipe_stack.dart';
import '../services/geolocator_service.dart';
import '../models/place.dart';
class CardSwipe extends StatelessWidget {
#override
Widget build(BuildContext context) {
final _currentPosition = Provider.of<Position>(context);
final _placesProvider = Provider.of<Future<List<Place>>>(context);
final _geoService = GeoLocatorService();
return FutureProvider(
create: (context) => _placesProvider,
child: Scaffold(
backgroundColor: Colors.grey[300],
body: (_currentPosition != null)
? Consumer<List<Place>>(
builder: (_, places, __) {
return (places != null)
? Column(
children: [
SizedBox(height: 10.0),
Container(
margin: EdgeInsets.only(top: 120.0),
height: 600,
child: SwipeStack(
children: places.map((place) {
return SwiperItem(builder:
(SwiperPosition position,
double progress) {
return FutureProvider(
create: (context) =>
_geoService.getDistance(
_currentPosition.latitude,
_currentPosition.longitude,
place.geometry.location.lat,
place.geometry.location.lng),
child: Consumer<double>(
builder: (_, distance, __) {
return (distance != null)
? Center(
child: Card(
child: Container(
height: 200,
width: 200,
child: Center(
child: Column(
mainAxisAlignment:
MainAxisAlignment
.center,
children: [
Text(place.name),
Text(
'${(distance / 1609).toStringAsFixed(3)} mi'), // convert meter to mi
],
),
),
),
),
)
: Container();
}),
);
});
}).toList(),
visibleCount: 3,
stackFrom: StackFrom.Top,
translationInterval: 6,
scaleInterval: 0.03,
onEnd: () => debugPrint("onEnd"),
onSwipe: (int index, SwiperPosition position) =>
debugPrint("onSwipe $index $position"),
onRewind:
(int index, SwiperPosition position) =>
debugPrint("onRewind $index $position"),
),
),
],
)
: Center(
child: CircularProgressIndicator(),
);
},
)
: Center(
child: CircularProgressIndicator(),
),
),
);
}
}
geolocator_service.dart
import 'package:geolocator/geolocator.dart';
class GeoLocatorService {
final geolocator = Geolocator();
Future<Position> getLocation() async {
return await geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
locationPermissionLevel: GeolocationPermission.location,
);
}
Future<double> getDistance(
double startLat, double startLng, double endLat, double endLng) async {
return await geolocator.distanceBetween(startLat, startLng, endLat, endLng);
}
}
place.dart
Quick note: Place class does import a custom class called geometry.dart however this is purely for structuring the Place object and I'm certain it doesn't affect the bug. Therefore, it has been omitted.
import './geometry.dart';
class Place {
final String name;
final Geometry geometry;
Place(this.name, this.geometry);
Place.fromJson(Map<dynamic, dynamic> parsedJson)
: name = parsedJson['name'],
geometry = Geometry.fromJson(
parsedJson['geometry'],
);
}
You have to add a key to the SwiperItem with some unique value (like the name of the place) since currently flutter thinks that the widget has stayed the same so the Consumer gets the state of the old topmost widget.
By adding the key you tell flutter that you removed the topmost widget and the new topmost is in fact the second widget
I have a page which is connected to appstate and viewmodel ,
what i'm doing in this page is picking an image from gallery and then sending it to the server , when i send i prompt a message to the user so he can see the loading ,
when the upload epic ends there is an action than goes to the reducer which change the state so the ui in the page will change ,
the reducer receives it and return a state , but the onDidChange not prompt right after ,
here's some code:
page build method :
#override
Widget build(BuildContext context) {
return new StoreConnector<AppState, AddRefundViewModel>(
converter: addRefundConverter,
onInitialBuild: (AddRefundViewModel vm) => {vm.doInitializeDto()},
builder: (context, vm) {
return MaterialApp(
title: 'Test',
home: Scaffold(
body: Column(
children: <Widget>[
Container(
child: new Column(
children: <Widget>[
RefundHeader1(context, vm),
RefundHeader(context, vm),
],
),
decoration: new BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerRight,
end: Alignment.bottomLeft,
colors: [primary, primaryGradient]),
),
width: MediaQuery.of(context).size.width * 1,
height: MediaQuery.of(context).size.width * 0.4,
),
//Text(vm.c),
refundRowSum(vm),
refundRowDate(context, vm),
refundRowCurrent(context, vm),
refundRowRefund(context, vm),
refundRowAtm(context, vm),
Expanded(child: Container(
child: GestureDetector(onTap: () {
//print("tap");}
// myFocusNode.dispose();},
if (myFocusNode != null) {
FocusScope.of(context).requestFocus(new FocusNode());
}
}),
)),
proceedMessage(context, vm),
],
),
bottomNavigationBar: BottomAppBar(
child: proceedButton(context, vm),
),
resizeToAvoidBottomPadding: false,
));
},
onDidChange: (vm) {
print('---!!!!-----<<<<<<<<<<<<<< onDidChange >>>>>>>>>>>-----!!!------');
if (vm.addRefundDto.tmpFileStat == TmpFileStat.BadExt) {
showSendReceiptDialog2(context, TmpFileStat.BadExt);
vm.doInitTmpFileStat();
} else if (vm.addRefundDto.tmpFileStat == TmpFileStat.TooLarge) {
showSendReceiptDialog2(context, TmpFileStat.TooLarge);
vm.doInitTmpFileStat();
}
else if (vm.addRefundDto.uploadRefundStatus ==
RefundUpload.Success ||vm.addRefundDto.uploadRefundStatus ==
RefundUpload.Started ||
vm.addRefundDto.uploadRefundStatus == RefundUpload.Failed) {
Navigator.pop(context);
showSendReceiptDialog(context, vm.addRefundDto.uploadRefundStatus);
}
},
);}
reducer :
case GotRefund:
print('----=== GotRefund add new refund reducer ===-----');
AddRefundDto refundDto = state.refundDto;
refundDto.uploadRefundStatus=RefundUpload.Success;
state.refundDto= refundDto;
return new AddRefundState(
fileDto: null,
byteImage: null,
refundDto: state.refundDto,
);
ADDED ViewModel :
import 'package:flutter/widgets.dart';
import 'package:iai/models/add_refund_dto.dart';
import 'package:iai/store/ui/ui_state.dart';
import 'package:iai/theme/images.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:iai/models/currency.dart';
class AddRefundViewModel {
bool fileAttachment;
DateTime pickedDate;
double amount;
bool isAtm;
bool canProceed;
AddRefundDto addRefundDto;
//final List<String> refundList;
final Map<String, AssetImage> refundList;
final Map<String, IconData> currencyList;
final List<Currency> currencyList2;
Function saveCurrentViewModel;
Function sendDtoToServer;
Function openGallery;
Function openCamera;
Function doInitializeDto;
Function doRemoveTmpImage;
Function doInitTmpFileStat;
final Function search;
final String searchTerm;
final bool showSearch;
AddRefundViewModel({
this.openCamera,
this.openGallery,
this.addRefundDto,
this.search,
this.searchTerm,
this.showSearch,
this.doInitializeDto,
this.doRemoveTmpImage,
this.doInitTmpFileStat,
this.refundList,
this.sendDtoToServer,
this.saveCurrentViewModel,
this.pickedDate,
this.amount,
this.currencyList,
this.isAtm,
this.canProceed,
this.currencyList2,
this.fileAttachment,
});
}
thanks to everyone that can contribute
Can you also post your AddRefundViewModel class in here? I think the on onDidChange is called based on those variables.