Could not navigate to initial route error when changing browser Url Flutter - flutter-web

I'm updating my code to use Navigator 2.0 and dough the navigation through NavigationBar's buttons works properly switching pages and updating the browser Url accordingly when I change it manually it throws an error:
Could not navigate to initial route.
The requested route name was: "/retailers"
There was no corresponding route in the app, and therefore the initial route specified will be ignored and "/" will be used instead.
Also back buttons is not working, and throws the Duplicate GlobalKey detected in widget tree.error.
Can the problem be that I check for routeInformation.location in my Parser?
edit
I tried putting the switch inside the uri.pathSegment.lenght check checking on uri.pathSegments.first and the back button now works dough still throwing the Duplicate GlobalKey detected in widget tree.error.
if (uri.pathSegments.length > 0) {
print(
'Uri.segments.first is: ${uri.pathSegments.first}..uri.path is: ${uri.path}');
// switch (routeInformation.location) {
switch (uri.pathSegments.first) {
...
This is my Parser:
class AppRouteInformationParser extends RouteInformationParser<RoutePath> {
#override
Future<RoutePath> parseRouteInformation(
RouteInformation routeInformation) async {
print(
'AppRouteInformationParser.parseRouteInformation called for ${routeInformation.location}');
final Uri uri = Uri.parse(routeInformation.location);
if (uri.pathSegments.length > 0) {
print(
'Uri.segments.first is: ${uri.pathSegments.first}, uri.path is: ${uri.path}');
} else {
print('AppRouteInformationParser uri has no segments and is $uri');
}
switch (routeInformation.location) {
// switch (uri.pathSegments.first) {
case '/':
print('AppRouteInformationParser.urlSegment switch case : /');
// return CyclistsPath();
return HomePath();
case CyclistsLandingRoute:
print(
'AppRouteInformationParser.routeInformation.location switch case: /cyclists');
return CyclistsPath();
case '/retailers':
print(
'AppRouteInformationParser.routeInformation.location switch case: /retailers');
return RetailersPath();
case '/map':
print(
'AppRouteInformationParser.routeInformation.location switch case: /map');
return MapPath();
case AboutRoute:
print(
'AppRouteInformationParser.routeInformation.location switch case: /about');
return AboutPath();
case TermsOfServiceRoute:
print(
'AppRouteInformationParser.routeInformation.location switch case: /terms-of-service');
return TermsOfServicePath();
case PrivacyPolicyRoute:
print(
'AppRouteInformationParser.routeInformation.location switch case: /privacy-policy');
return PrivacyPolicyPath();
case PrivacySettingsRoute:
print(
'AppRouteInformationParser.routeInformation.location switch case: /privacy-settings');
return PrivacySettingsPath();
case CommunityGuidelinesRoute:
print(
'AppRouteInformationParser.routeInformation.location switch case: /community-guidelines');
return CommunityGuidelinesPath();
case LegalNoticeRoute:
print(
'AppRouteInformationParser.routeInformation.location switch case: /legal-notice');
return LegalPath();
default:
print(
'### default AppRouteInformationParser.routeInformation.location switch case ## default: /');
return HomePath();
}
}
#override
RouteInformation restoreRouteInformation(RoutePath path) {
print(
'AppRouteInformationParser.restoreRouteInformation called for path ${path.selectedPath}');
switch (path.selectedPath) {
case '/':
// case CyclistsLandingRoute:
print('restoreRouteInformation RouteInformation.location: /');
return RouteInformation(location: '/');
case '/cyclists':
// case CyclistsLandingRoute:
print('restoreRouteInformation RouteInformation.location: /cyclists');
return RouteInformation(location: '/cyclists');
case '/retailers':
print('restoreRouteInformation RouteInformation.location: /retailers');
return RouteInformation(location: '/retailers');
case '/map':
print('restoreRouteInformation RouteInformation.location: /map');
return RouteInformation(location: '/map');
case '/about':
print('restoreRouteInformation RouteInformation.location: /about');
return RouteInformation(location: '/about');
case '/terms-of-service':
print(
'restoreRouteInformation RouteInformation.location: /terms-of-service');
return RouteInformation(location: '/terms-of-service');
case '/privacy-policy':
print(
'restoreRouteInformation RouteInformation.location: /privacy-policy');
return RouteInformation(location: '/privacy-policy');
case '/privacy-settings':
print(
'restoreRouteInformation RouteInformation.location: /privacy-settings');
return RouteInformation(location: '/privacy-settings');
case '/community-guidelines':
print(
'restoreRouteInformation RouteInformation.location: /community-guidelines');
return RouteInformation(location: '/community-guidelines');
case '/legal-notice':
print(
'restoreRouteInformation RouteInformation.location: /legal-notice');
return RouteInformation(location: '/legal-notice');
default:
print(
'restoreRouteInformation ### Default RouteInformation.location: /cyclists');
return RouteInformation(location: '/cyclists');
}
}
}
I also noticed through the prints I set that there might be a weird loop when the app first loads:
Parser
AppRouteInformationParser.parseRouteInformation called for /
AppRouteInformationParser uri has no segments and is /
AppRouteInformationParser.urlSegment switch case : /
RuterDelegate
RouterDelegate.currentConfiguration appState.selectedPage is
Parser
AppRouteInformationParser.restoreRouteInformation called for path /
restoreRouteInformation RouteInformation.location: /
RouterDelegate
RouterDelegate.setNewRoutePath path is /
AppState
AppState setting selectedPage to /
which triggers delegate build, so again
RouterDelegate
RouterDelegate.currentConfiguration appState.selectedPage is /
Parser
AppRouteInformationParser.restoreRouteInformation called for path /
restoreRouteInformation RouteInformation.location: /
Non expected prints
RouterDelegate
RouterDelegate.currentConfiguration appState.selectedPage is /
Parser
AppRouteInformationParser.restoreRouteInformation called for path /
restoreRouteInformation RouteInformation.location: /
As when a button is pressesed then I only get :
Button
1.selected tapped is /about
AppState
AppState setting selectedPage to /about
RouterDelegate
RouterDelegate.currentConfiguration appState.selectedPage is /about
Parser
AppRouteInformationParser.restoreRouteInformation called for path /about
restoreRouteInformation RouteInformation.location: /about

After a couple of days of struggling I finally found the problem:
In main.dart build method I was returning a MaterialApp with a MaterialApp.router as its home: instead that returning a MaterialApp.router directly and move all the MaterialApp configuration parameters into it.
Everything works just as expected now.
wrong way :
AppRouterDelegate _routerDelegate = AppRouterDelegate();
AppRouteInformationParser _routeInformationParser =
AppRouteInformationParser();
#override
Widget build(BuildContext context) {
return MaterialApp(
title: '',
color: Colors.red,
localizationsDelegates: [
const AppLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
const Locale('en', 'US'),
const Locale('it', 'IT')
// const Locale('es', 'ES'),
],
localeResolutionCallback:
(Locale locale, Iterable<Locale> supportedLocales) {
for (Locale supportedLocale in supportedLocales) {
if (supportedLocale.languageCode == locale.languageCode ||
supportedLocale.countryCode == locale.countryCode) {
print('Web device Locale is $locale');
return supportedLocale;
}
}
return supportedLocales.first;
},
debugShowCheckedModeBanner: false,
home: MaterialApp.router(
routeInformationParser: _routeInformationParser,
routerDelegate: _routerDelegate),
);
}
correct way is :
AppRouterDelegate _routerDelegate = AppRouterDelegate();
AppRouteInformationParser _routeInformationParser =
AppRouteInformationParser();
#override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationParser: _routeInformationParser,
routerDelegate: _routerDelegate,
debugShowCheckedModeBanner: false,
title: '',
color: Colors.red,
localizationsDelegates: [
const AppLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
const Locale('en', 'US'),
const Locale('it', 'IT')
// const Locale('es', 'ES'),
],
localeResolutionCallback:
(Locale locale, Iterable<Locale> supportedLocales) {
for (Locale supportedLocale in supportedLocales) {
// if (UniversalPlatform.isWeb) {
if (supportedLocale.languageCode == locale.languageCode ||
supportedLocale.countryCode == locale.countryCode) {
print('Web device Locale is $locale');
return supportedLocale;
}
}
return supportedLocales.first;
},
// localeListResolutionCallback: ,
);
}

Related

Flutter CircularProgressIndicator on top of syncfusion_calendar

I am struggling with correct futurebuilder positioning for last few days. Im using syncfusion_calendar package to display json data from my API, where i call a new reqest to API every time user changes calendars month. The problem is that user is not being told about ongoing data downlad and i would love to do that by showing CircularProgressIndicator instead of calendar while its loading.
my pubspec file just in case :
name: flutter_viaapp_startmenu
description: A new Flutter application.
# The following line prevents the package from being accidentally published to
# pub.dev using `pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
firebase_core: ^0.5.0+1
cloud_firestore: ^0.14.4
firebase_messaging: ^7.0.3
firebase_in_app_messaging: 0.2.3
webview_flutter: ^1.0.7
flutter_staggered_grid_view: ^0.3.3
easy_localization: ^2.3.2
intl: ^0.16.1
http: ^0.12.2
syncfusion_flutter_calendar: ^18.3.51
shared_preferences: ^0.5.12
flutter_local_notifications: ^3.0.3
flutter_localizations:
sdk: flutter
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.0
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets:
- assets/menu.jpg
- assets/welcome.jpg
- assets/translations/en.json
- assets/translations/lv.json
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
My main calendar file :
import 'dart:async';
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:syncfusion_flutter_calendar/calendar.dart';
import 'package:intl/intl.dart';
class Lecture_graph extends StatefulWidget {
Lecture_graph({Key key}) : super(key: key);
#override
State<StatefulWidget> createState() => _MyLecturesGraphState();
}
class _MyLecturesGraphState extends State<Lecture_graph> {
Future<List<Lecture>> _future;
List<Lecture> lectures;
DateTime _selectedDate = new DateTime.now();
List<LectureTime> _times;
//TODO make this empty after SO post
var coursecode = "IT3";
#override
void initState() {
_selectedDate = new DateTime(
_selectedDate.year,
_selectedDate.month,
15,
_selectedDate.hour,
_selectedDate.minute,
_selectedDate.second,
_selectedDate.millisecond,
_selectedDate.microsecond);
_future = downloadData();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(coursecode + " | Lectures"),
actions: [
LecturesNavigationControls(),
],
),
body: lectureGraphList());
}
Future<String> _checkSavedCourse() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String _coursecode = prefs.getString('savedCourse');
if (_coursecode == "" || _coursecode == null) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CourseSelectionPage()),
);
return null;
} else {
return _coursecode;
}
}
Widget lectureGraphList() {
return FutureBuilder<List<Lecture>>(
future: _future,
builder: (BuildContext context, AsyncSnapshot<List<Lecture>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: SizedBox(
child: const Expanded(
child: Center(child: const CircularProgressIndicator())),
width: 100,
height: 100,
),
);
} else {
if (snapshot.hasError)
return Center(child: Text('Error: ${snapshot.error}'));
else
return showLectures(lectures);
}
},
);
}
//THIS FUNCTION IS CALLED EVERY TIME TO DOWNLOAD NEW DATA FROM API
Future<List<Lecture>> downloadData() async {
//get saved course
if (coursecode == "" || coursecode == null) {
coursecode = await _checkSavedCourse();
//debug
print('courscode recieved from sharedprefs');
}
//if there is no date selected, select today
if (_selectedDate == null) _selectedDate = new DateTime.now();
//build request URL
var requestURL =
'https://lekcijas.va.lv/lekcijas_android/getMonthLectures.php?date=' +
DateFormat('yyyy-MM').format(_selectedDate) +
"&breaks&program=" +
coursecode;
//wait for response
var response = await http.get(requestURL);
var data = json.decode(response.body)["result"];
//clear array after each request
if (lectures != null) lectures.clear();
try {
//create lectures from json response
lectures = List<Lecture>.from(data.map((x) => Lecture.fromJson(x)));
_getDataSource(lectures);
} catch (e) {
print(e.toString());
}
return Future.value(lectures);
}
Widget showLectures(List<Lecture> lectures) {
return Card(
child: Row(
children: [
Expanded(
child: SfCalendar(
view: CalendarView.month,
firstDayOfWeek: 1,
onViewChanged: (ViewChangedDetails details) {
if (_selectedDate.month != details.visibleDates[15].month) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_selectedDate = details.visibleDates[15];
setState(() {
//CALENDAR MONTH CHANGE IS CALLED HERE
downloadData();
});
});
}
},
dataSource: LectureTimeDataSource(_times),
monthViewSettings: MonthViewSettings(
appointmentDisplayMode:
MonthAppointmentDisplayMode.indicator,
showAgenda: true,
agendaStyle: AgendaStyle(
appointmentTextStyle:
TextStyle(color: Colors.black))),
showNavigationArrow: true))
],
),
);
}
void _getDataSource(List<Lecture> lectures) {
var lectureTimes = <LectureTime>[];
lectures.forEach((element) {
lectureTimes.add(LectureTime(
(element.classroom + " " + element.lecture),
DateTime.parse(element.datums + " " + element.start),
DateTime.parse(element.datums + " " + element.end),
hexToColor(element.color),
false));
});
setState(() {
_times = lectureTimes;
});
}
}
class LecturesNavigationControls extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
IconButton(
//TODO find normal icon
icon: const Icon(Icons.wheelchair_pickup),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CourseSelectionPage()),
);
},
),
],
);
}
}
class LectureTimeDataSource extends CalendarDataSource {
LectureTimeDataSource(List<LectureTime> source) {
appointments = source;
}
#override
DateTime getStartTime(int index) {
return appointments[index].from;
}
#override
DateTime getEndTime(int index) {
return appointments[index].to;
}
#override
String getSubject(int index) {
return appointments[index].eventName;
}
#override
Color getColor(int index) {
return appointments[index].background;
}
#override
bool isAllDay(int index) {
return appointments[index].isAllDay;
}
}
class LectureTime {
LectureTime(
this.eventName, this.from, this.to, this.background, this.isAllDay);
String eventName;
DateTime from;
DateTime to;
Color background;
bool isAllDay;
}
Color hexToColor(String code) {
return new Color(int.parse(code.substring(1, 7), radix: 16) + 0xFF000000);
}
class Lecture{
final String programs;
final String lecture;
final String lecturer;
final String start;
final String end;
final String classroom;
final String color;
final String datums;
Lecture({this.programs, this.lecture, this.lecturer, this.start, this.end, this.classroom, this.color, this.datums});
factory Lecture.fromJson(Map<String, dynamic> json) {
return Lecture(
programs: json['nodala'] as String,
lecture: json['kurss'] as String,
lecturer : json['lektors'] as String,
start: json['sakums'] as String,
end: json['beigas'] as String,
classroom: json['nosaukums'] as String,
color: json['iela'] as String,
datums: json['datums'] as String,
);
}
}
class LectureTime {
LectureTime(
this.eventName, this.from, this.to, this.background, this.isAllDay);
String eventName;
DateTime from;
DateTime to;
Color background;
bool isAllDay;
}
please use "IT3" string as coursecode for API.
API request url example here
You can add a variable called downloadingData and set it to false by default. Then, before calling downloadData() set it to true and when the function finishes, set it back to false.
Finally, inside the build method:
child: downloadingData ? CircularProgressIndicator() : SfCalendar(...)
Based on the provided information and code snippet, we have checked, and your requirement is “Showing the CircularProgressIndicator when loading calendar”. We have prepared a simple sample for loading circular progress indicator with loading online data to the calendar. Please find the sample from the following link,
Sample link:
https://www.syncfusion.com/downloads/support/directtrac/312448/ze/minimum_appointmentduration298839661.zip
Also, we have a KB document for loading the online data to Flutter calendar with a simple loading text message. In the same way, you will use CircularProgressIndicator.
KB link: https://www.syncfusion.com/kb/11568/how-to-load-the-json-data-online-to-the-flutter-event-calendar-sfcalendar-appointments
We hope that the above sample and KB helps you. Please let us know if you need further assistance.

Dart Map and Parsing JSON

As a new Dart Fan, I would like to understand the concept of Map/List.
I tried to do HTTP requests, getting JSON data. And it's ok till I have to assign to the Map.
Let me show you the example of JSON data:
{
"error":"",
"error_number":"",
"response_code":200,
"result":[
{
"id":1,
"name":"Great Deal",
"day_aired":"2015-07-05 11:06:09",
"trend":"Noone",
"trend_details": [{
"name":"Great Deal",
}
]
},
{
"id":2,
....
}
]
}
The code:
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<ApiResponse> fetchData(String command, Map params) async {
final String url =
'https://example.com/api/v2/....';
final response = await http.get(url);
if (response.statusCode == 200) {
return ApiResponse.fromJson(json.decode(response.body));
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
}
final response = await http.get(url);
dynamic data = json.decode(response.body);
List<String> parsed = data['result'] as List<String>;
// List<String> parsedList = new List<String>.from(parsed);
if (response.statusCode == 200) {
//return json.decode(response.body);
List<ApiResponse> list = List<ApiResponse>.from(
parsed.map((i) => ApiResponse.fromJson(i as Map<String, dynamic>)));
}
I do the same as this article. But I read this article too. I'm trying to create Future<ApiResponse> with data from json.decode(response.body) (result entry inside of it).
factory ApiResponse.fromJson(Map<String, dynamic> json) {...}
But as I understand, result is not Map<String, dynamic> but when I try to invoke the code below it says:
Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<String>' in type cast and it referred to List<String> parsed = data['result'] as List<String>;.
I'm confused and I know the code is a mess. I read in the second article that I should do an additional cast to trend_details but it did not work as I expected. Obviously data['result'] is an array but how to cast it properly? What are the good practices?
result stores a list of Map<String, dynamic>
final parsed = data['result'] as List<Map<String, dynamic>>;
You can parse json string with the following structure and code
You can see picture display correct result name
code snippet
var payload = payloadFromJson(jsonStr);
print('${payload.result[0].name}');
related class
// To parse this JSON data, do
//
// final payload = payloadFromJson(jsonString);
import 'dart:convert';
Payload payloadFromJson(String str) => Payload.fromJson(json.decode(str));
String payloadToJson(Payload data) => json.encode(data.toJson());
class Payload {
String error;
String errorNumber;
int responseCode;
List<Result> result;
Payload({
this.error,
this.errorNumber,
this.responseCode,
this.result,
});
factory Payload.fromJson(Map<String, dynamic> json) => Payload(
error: json["error"] == null ? null : json["error"],
errorNumber: json["error_number"] == null ? null : json["error_number"],
responseCode: json["response_code"] == null ? null : json["response_code"],
result: json["result"] == null ? null : List<Result>.from(json["result"].map((x) => Result.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"error": error == null ? null : error,
"error_number": errorNumber == null ? null : errorNumber,
"response_code": responseCode == null ? null : responseCode,
"result": result == null ? null : List<dynamic>.from(result.map((x) => x.toJson())),
};
}
class Result {
int id;
String name;
DateTime dayAired;
String trend;
List<TrendDetail> trendDetails;
Result({
this.id,
this.name,
this.dayAired,
this.trend,
this.trendDetails,
});
factory Result.fromJson(Map<String, dynamic> json) => Result(
id: json["id"] == null ? null : json["id"],
name: json["name"] == null ? null : json["name"],
dayAired: json["day_aired"] == null ? null : DateTime.parse(json["day_aired"]),
trend: json["trend"] == null ? null : json["trend"],
trendDetails: json["trend_details"] == null ? null : List<TrendDetail>.from(json["trend_details"].map((x) => TrendDetail.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"id": id == null ? null : id,
"name": name == null ? null : name,
"day_aired": dayAired == null ? null : dayAired.toIso8601String(),
"trend": trend == null ? null : trend,
"trend_details": trendDetails == null ? null : List<dynamic>.from(trendDetails.map((x) => x.toJson())),
};
}
class TrendDetail {
String name;
TrendDetail({
this.name,
});
factory TrendDetail.fromJson(Map<String, dynamic> json) => TrendDetail(
name: json["name"] == null ? null : json["name"],
);
Map<String, dynamic> toJson() => {
"name": name == null ? null : name,
};
}
full code
import 'package:flutter/material.dart';
// To parse this JSON data, do
//
// final payload = payloadFromJson(jsonString);
import 'dart:convert';
Payload payloadFromJson(String str) => Payload.fromJson(json.decode(str));
String payloadToJson(Payload data) => json.encode(data.toJson());
class Payload {
String error;
String errorNumber;
int responseCode;
List<Result> result;
Payload({
this.error,
this.errorNumber,
this.responseCode,
this.result,
});
factory Payload.fromJson(Map<String, dynamic> json) => Payload(
error: json["error"] == null ? null : json["error"],
errorNumber: json["error_number"] == null ? null : json["error_number"],
responseCode: json["response_code"] == null ? null : json["response_code"],
result: json["result"] == null ? null : List<Result>.from(json["result"].map((x) => Result.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"error": error == null ? null : error,
"error_number": errorNumber == null ? null : errorNumber,
"response_code": responseCode == null ? null : responseCode,
"result": result == null ? null : List<dynamic>.from(result.map((x) => x.toJson())),
};
}
class Result {
int id;
String name;
DateTime dayAired;
String trend;
List<TrendDetail> trendDetails;
Result({
this.id,
this.name,
this.dayAired,
this.trend,
this.trendDetails,
});
factory Result.fromJson(Map<String, dynamic> json) => Result(
id: json["id"] == null ? null : json["id"],
name: json["name"] == null ? null : json["name"],
dayAired: json["day_aired"] == null ? null : DateTime.parse(json["day_aired"]),
trend: json["trend"] == null ? null : json["trend"],
trendDetails: json["trend_details"] == null ? null : List<TrendDetail>.from(json["trend_details"].map((x) => TrendDetail.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"id": id == null ? null : id,
"name": name == null ? null : name,
"day_aired": dayAired == null ? null : dayAired.toIso8601String(),
"trend": trend == null ? null : trend,
"trend_details": trendDetails == null ? null : List<dynamic>.from(trendDetails.map((x) => x.toJson())),
};
}
class TrendDetail {
String name;
TrendDetail({
this.name,
});
factory TrendDetail.fromJson(Map<String, dynamic> json) => TrendDetail(
name: json["name"] == null ? null : json["name"],
);
Map<String, dynamic> toJson() => {
"name": name == null ? null : name,
};
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
String jsonStr = '''
{
"error":"",
"error_number":"",
"response_code":200,
"result":[
{
"id":1,
"name":"Great Deal",
"day_aired":"2015-07-05 11:06:09",
"trend":"Noone",
"trend_details": [{
"name":"Great Deal"
}
]
}
]
}
''';
void _incrementCounter() {
var payload = payloadFromJson(jsonStr);
print('${payload.result[0].name}');
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}

RedirectToAction inside a method doesn't work

Hello i have this method
private ActionResult CheckResult(ReactivationResponse result, GlobalObject globalInfo)
{
if (result == null)
{
return RedirectToAction("Failed", "Redirect", new { errorCode = 1014 });
}
else if (!result.IsReactivationSuccess && !result.IsOrderImported && !globalInfo.MemberInfo.IsWinbackAplicable)
{
return RedirectToAction("Failed", "Redirect", new { errorCode = 201 });
}
else if (!result.IsReactivationSuccess && result.Errors.Any())
{
if (result.Errors.Any(e => e.Message == "ApprovalPending"))
{
return View("Pending");
}
return RedirectToAction("Failed", "Redirect", new { errorCode = result.Errors.FirstOrDefault().StackTrace });
}
return null;
}
inside another Action Result
public ActionResult OtherMethod()
{
CheckResult(result, globalInfo);
//More code
return View()
}
I'm trying to redirect the code according to the result, and in case it doesn't apply, that the app continue and return the normal view.
But it doesn't work, if any of the if statements applies it doesn't redirect to anywhere, it continues with the normal viw.
I also tried to put a return before the method
return CheckResult(result, globalInfo);
and it works except if my method returns null, then it doesn't continue with the app.
I want to evaluate if it needs to redirect or if it should continue

How to define different context menus for different objects in autodesk forge

I want to define different context menus for different objects in forge viewer,this is my code
viewer.addEventListener(Autodesk.Viewing.AGGREGATE_SELECTION_CHANGED_EVENT,function(e){
if(viewer.getSelection().length==0){return;}
var selectId=viewer.getSelection()[0];
viewer.search("Cabinet",function(ids){
if(ids.indexOf(selectId)!=-1){
viewer.registerContextMenuCallback('CabinetMsg', function (menu, status) {
if (status.hasSelected) {
menu.push({
title: "CabinetMsg",
target: function () {
openLayer('CabinetMsg','954','775','CabinetMsg.html')
}
});
}
});
}else{
viewer.registerContextMenuCallback('CabinetMsg', function (menu, status) {
if (status.hasSelected) {
menu.forEach(function(el,index){
if(el.title=="CabinetMsg"){
menu.splice(menu.indexOf(index),1)
}
})
}
});
}
})
});
But push elements to the array is always later than the context menus show. My custom context menu is always show when I select another object. What I can do?
The codes you provided will create 2 new sub items to the context menu. Here is a way for this case, i.e. you have to write your own ViewerObjectContextMenu. In addition, you need do hitTest in ViewerObjectContextMenu.buildMenu to get dbId selected by the mouse right clicking. Here is the example for you:
class MyContextMenu extends Autodesk.Viewing.Extensions.ViewerObjectContextMenu {
constructor( viewer ) {
super( viewer );
}
isCabinet( dbId ) {
// Your logic for determining if selected element is cabinet or not.
return false;
}
buildMenu( event, status ) {
const menu = super.buildMenu( event, status );
const viewport = this.viewer.container.getBoundingClientRect();
const canvasX = event.clientX - viewport.left;
const canvasY = event.clientY - viewport.top;
const result = that.viewer.impl.hitTest(canvasX, canvasY, false);
if( !result || !result.dbId ) return menu;
if( status.hasSelected && this.isCabinet( result.dbId ) ) {
menu.push({
title: 'CabinetMsg',
target: function () {
openLayer( 'CabinetMsg', '954', '775', 'CabinetMsg.html' );
}
});
}
return menu;
}
}
After this, you could write an extension to replace default viewer context menu with your own menu. Here also is the example:
class MyContextMenuExtension extends Autodesk.Viewing.Extension {
constructor( viewer, options ) {
super( viewer, options );
}
load() {
this.viewer.setContextMenu( new MyContextMenu( this.viewer ) );
return true;
}
unload() {
this.viewer.setContextMenu( new Autodesk.Viewing.Extensions.ViewerObjectContextMenu( this.viewer ) );
return true;
}
}
Hope this help.

groovy multithreading

I'm newbie to groovy/grails.
How to implement thread for this code . Had 2500 urls and this was taking hours of time for checking each url.
so i decided to implement multi-thread for this :
Here is my sample code :
def urls = [
"http://www.wordpress.com",
"http://67.192.103.225/QRA.Public/" ,
"http://www.subaru.com",
"http://baldwinfilter.com/products/start.html"
]
def up = urls.collect { ur ->
try {
def url = new URL(ur)
def connection = url.openConnection()
if (connection.responseCode == 200) {
return true
} else {
return false
}
} catch (Exception e) {
return false
}
}
For this code i need to implement multi-threading .
Could any one please suggest me the code.
thanks in advance,
sri.
I would take a look at the Groovy Parallel Systems library. In particular I think that the Parallel collections section would be useful.
Looking at the docs, I believe that collectParallel is a direct drop-in replacement for collect (bearing in mind the obvious caveats about side-effects). The following works fine for me:
def urls = [
"http://www.wordpress.com",
"http://www.subaru.com",
"http://baldwinfilter.com/products/start.html"
]
Parallelizer.doParallel {
def up = urls.collectParallel { ur ->
try {
def url = new URL(ur)
def connection = url.openConnection()
if (connection.responseCode == 200) {
return true
} else {
return false
}
} catch (Exception e) {
return false
}
}
println up
}
See the Groovy docs for an example how to use an ExecutorService to do what you want.
You can use this to check the URL in a separate thread.
class URLReader implements Runnable
{
def valid
def url
URLReader( url ) {
this.url = url
}
void run() {
try {
def connection = url.toURL().openConnection()
valid = ( connection.responseCode == 200 ) as Boolean
} catch ( Exception e ) {
println e.message
valid = Boolean.FALSE
}
}
}
def reader = new URLReader( "http://www.google.com" )
new Thread( reader ).start()
while ( reader.valid == null )
{
Thread.sleep( 500 )
}
println "valid: ${reader.valid}"
Notes: The valid attribute will be either null, Boolean.TRUE or Boolean.FALSE. You'll need to wait for a while to give all the threads a chance to open the connection. Depending on the number of URLs you're checking you will eventually hit a limit of the number of threads / connections you can realistically handle, so should check URLs in batches of the appropriate size.
I think this way is very simple to achieve.
import java.util.concurrent.*
//Thread number
THREADS = 100
pool = Executors.newFixedThreadPool(THREADS)
defer = { c -> pool.submit(c as Callable) }
def urls = [
"http://www.wordpress.com",
"http://www.subaru.com",
]
def getUrl = { url ->
def connection = url.openConnection()
if (connection.responseCode == 200) {
return true
} else {
return false
}
}
def up = urls.collect { ur ->
try {
def url = new URL(ur)
defer{ getUrl(url) }.get()
} catch (Exception e) {
return false
}
}
println up
pool.shutdown()
This is how I implemented:
class ValidateLinks extends Thread{
def valid
def url
ValidateLinks( url ) {
this.url = url
}
void run() {
try {
def connection = url.toURL().openConnection()
connection.setConnectTimeout(5000)
valid = ( connection.responseCode == 200 ) as Boolean
} catch ( Exception e ) {
println url + "-" + e.message
valid = Boolean.FALSE
}
}
}
def threads = [];
urls.each { ur ->
def reader = new ValidateLinks(ur.site_url)
reader.start()
threads.add(reader);
}
while (threads.size() > 0) {
for(int i =0; i < threads.size();i++) {
def tr = threads.get(i);
if (!tr.isAlive()) {
println "URL : " + tr.url + "Valid " + tr.valid
threads.remove(i);
i--;
}
}
}

Resources