I'm building booking application and currently I'm facing this issue where the use can select a range of days using ShowDateRangePicker, showDateRangePicker, however the use can select any range within the start and end dates but I'm asked to not let user select more than 14 days. For Example:
Startdate = 12/2/2023
endDate = 1/1/2024
and the user selected range: 12/2/2023 - 28/2/2023
In this case it should throw an error because the range exceeded the limit of 14 days. the difference in range exceeded 14.
Or a better one when the user reach a from date + 14 it will stop allowing them to select more days.
You can use syncfusion_flutter_datepicker library. It has a selectionChanged callback that you can manipulate to limit selectable dates on the go. The snippet below shows how to limit the range to 14 days from selected _start day.
class Home extends StatefulWidget {
const Home({super.key});
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
final DateTime _minDate = DateTime.now();
DateTime _maxDate = DateTime.now().add(const Duration(days: 365));
final Duration _duration = const Duration(days: 14);
DateTime _start = DateTime.now();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SfDateRangePicker(
minDate: _minDate,
maxDate: _maxDate,
selectionMode: DateRangePickerSelectionMode.range,
onSelectionChanged: (DateRangePickerSelectionChangedArgs args) {
if (args.value is PickerDateRange) {
_start = (args.value as PickerDateRange).startDate!;
setState(() {
// limit the maxDate to 14 days from selected date
_maxDate = _start.add(_duration);
});
}
},
)),
);
}
}
For more customization refer to docs.
Related
I have an app which gets hours and minutes from the backend. Every time the app is called the data from the backend gets saved in shared preferences. When he user has no internet connection I show the same screen as the user saw when having internet just using the data saved in shared preferences instead. One of the parts of the data is a timer which I get the hours and minutes from the backend, and the hours and minutes get updated every time I make the API call. What I want now is to have the data from shared preferences to create a timer with the data saved in shared preferences. I need to have the minutes and hours update and work just like it would with the normal data with internet connection. So when there is no internet connection we display the data and I need to create the timer to update the minutes and the hours so the user can see the timer update even when there is no internet. So if the minutes and hours in shared preferences are saved like: 1hr : 6mins. I need to make it so the time keeps going and minutes and hours keep updating. So after 60 secs mins will be 7mins, and after 54mins hours will be 2hrs, And the process starts right when the screen is opened without any start button.
// Saving data from api in shared preferences
body: FutureBuilder<Response>(
future: futureDataForStatus,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) {
accountInfo = WorkingLocationStatus.fromJson(
json.decode(snapshot.data!.body),
);
final duration = IsoDuration.parse(
accountInfo!.duration.toString(),
);
prefs.setDouble('workingHours', duration.hours);
prefs.setDouble('workingMinutes', duration.minutes);
return Column(
// Displaying the saved data
class OffilneWorkingHoursMinutes extends StatefulWidget {
const OffilneWorkingHoursMinutes({Key? key}) : super(key: key);
#override
State<OffilneWorkingHoursMinutes> createState() =>
_OffilneWorkingHoursMinutesState();
}
class _OffilneWorkingHoursMinutesState
extends State<OffilneWorkingHoursMinutes> {
#override
Widget build(BuildContext context) {
return Center(
child: Text(
'${prefs.getDouble('workingHours')!.toStringAsFixed(0)} hrs - '
'${prefs.getDouble('workingMinutes')!.toStringAsFixed(0)} mins ',
style: const TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
),
);
}
}
Look at this example, I think it could help, just adjust it to your needs:
class OffilneWorkingHoursMinutes extends StatefulWidget {
const OffilneWorkingHoursMinutes({Key? key}) : super(key: key);
#override
State<OffilneWorkingHoursMinutes> createState() =>
_OffilneWorkingHoursMinutesState();
}
class _OffilneWorkingHoursMinutesState
extends State<OffilneWorkingHoursMinutes> {
var time = Time(hours: 1, minutes: 6, seconds: 0); // pass your time from backend here
#override
void initState() {
Timer.periodic(const Duration(seconds: 1), (timer) { // use timer when you are offline and cancel it when you are back online
setState(() {
if (time.seconds < 59) {
time.seconds++;
} else {
if (time.minutes < 59) {
time.minutes++;
} else {
time.minutes = 0;
time.hours++;
}
time.seconds = 0;
}
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Center(
child: Text(
'${time.hours} hrs - '
'${time.minutes} mins - '
'${time.seconds} sec ',
style: const TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
),
);
}
}
class Time {
int hours;
int minutes;
int seconds;
Time({
this.hours = 0,
this.minutes = 0,
this.seconds = 0,
});
}
Is this way of coding correct, and how do show 2 dates. Can someone help me to check and correct my coding? int ts=1646274840000; int ts2=1646015654686;
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'api_service.dart';
class AppoinmentList extends StatefulWidget {
final String? token;
AppoinmentList({
Key? key,
this.token
}) : super(key: key);
#override
_AppoinmentListState createState() => _AppoinmentListState();
}
class _AppoinmentListState extends State<AppoinmentList> {
#override
void initState() {
super.initState();
APIService.getAppointmentList(widget.token!);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Appointment Listing"),
),
body: _time()
);
//body: _appoinmentListUI(),
}
}
_time() {
int ts=1646274840000;
int ts2=1646015654686;
DateTime tsdate = DateTime.fromMillisecondsSinceEpoch(ts);
DateTime ts2date = DateTime.fromMillisecondsSinceEpoch(ts2);
String fdatetime = DateFormat('MM/dd/yyyy, hh:mm a').format(tsdate);
String fdatetime2 = DateFormat('MM/dd/yyyy, hh:mm a').format(ts2date);
return Container(
child: Text(fdatetime,),
);
}
I only success to show the output for one date only. How to show two dates? Someone can help me.
This output show for one date only
_time() only returns one Text widget for the first date. You need to add another one for the second date.
Put both Text widgets in a Column if you want them on top of each other.
like this:
_time() {
int ts = 1646274840000;
int ts2 = 1646015654686;
DateTime tsdate = DateTime.fromMillisecondsSinceEpoch(ts);
DateTime ts2date = DateTime.fromMillisecondsSinceEpoch(ts2);
String fdatetime = DateFormat('MM/dd/yyyy, hh:mm a').format(tsdate);
String fdatetime2 = DateFormat('MM/dd/yyyy, hh:mm a').format(ts2date);
return Column(
// To make children align to the left of the screen
crossAxisAlignment: CrossAxisAlignment.start,
// to prevent `Column` from expanding.
mainAxisSize: MainAxisSize.min,
children: [
Text(fdatetime),
Text(fdatetime2),
],
);
}
I'm trying to add a text field that will get the date in the input field. I'm using InputDatePickerFormField widget. The issue I'm finding that it does not show error when the date is incorrect.
Here is my code:
class _BirthDay extends StatefulWidget {
#override
__BirthDayState createState() => __BirthDayState();
}
class __BirthDayState extends State<_BirthDay> {
DateTime? selectedDate;
#override
Widget build(BuildContext context) {
final firstDate = DateTime(DateTime.now().year - 120);
final lastDate = DateTime.now();
return InputDatePickerFormField(
firstDate: firstDate,
lastDate: lastDate,
fieldLabelText: '${AppLocalizations.of(context)!.dateOfBirth}',
errorFormatText: '${AppLocalizations.of(context)!.dateOfBirthInvalid}',
errorInvalidText: '${AppLocalizations.of(context)!.dateOfBirthInvalid}',
onDateSubmitted: (date) {
print(date);
setState(() {
selectedDate = date;
});
},
onDateSaved: (date) {
print(date);
setState(() {
selectedDate = date;
});
},
);
}
}
One way that you can add a checker on your Text fields is by setting the fields as children of a Form. Using this, you'll be able to validate the values on your fields once submitted.
final _formKey = GlobalKey<FormState>();
...
Form(
key: _formKey,
child: InputDatePickerFormField(...),
)
Then you can run a check using _formKey.currentState!.validate()). Trigger this validation on any onClick or onPressed event.
You need to save the form to see the validations errors
_formKey2.currentState.save();
You can call it on the submit button
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I’m a beginner when it comes to coding. I just started using flutter and want to make a morning devotion app for church.
I’m currently using the routes method to join pages for month and day but I just realized I have to do the same for every single day
As in :
January > Day one
Day two, three and so on.
Is there a more efficient way to do this?
these are the routes I have so far. The loading screen, home, devotion, months, January etc
'''dart
void main()=>runApp(MaterialApp(
initialRoute: "/",
routes: {
"/": (context)=> loading(),
"/home":(context)=>home(),
"/Devotion":(context)=>Dpg(),
"/Months":(context)=>months(),
"/jan":(context)=>jan(),
"/feb":(context)=>feb(),
},
));
'''
Right now i want to work for the month of january so there will have to be pages for Day one to 31 and then February all the way to december. Im not so sure i have to continue with
"/JAN Day one":(context)=>jd1(),
"/JAN Day two":(context)=>jd2(),
then go to
"/FEB Day one":(context)=>fb1(),
etc.
is there a better way to do this?
Welcome to Stack Overflow! If I understand your question correctly, you are currently defining your routes using the routes parameter similar to this:
MaterialApp(
routes: {
'/01-01': (context) {
return Scaffold(
appBar: AppBar(
title: const Text('01 JAN'),
),
);
},
'/02-01': (context) {
return Scaffold(
appBar: AppBar(
title: const Text('02 JAN),
),
);
},
},
)
Instead of defining each route manually, you could investigate using the new Navigator 2.0 changes to easily read parameters from the URL similar to this:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(App());
}
class App extends StatefulWidget {
#override
_AppState createState() => _AppState();
}
class _AppState extends State<App> {
final _routeInformationParser = AppRouteInformationParser();
final _routerStateData = RouterStateData();
late AppRouterDelegate _routerDelegate;
#override
Widget build(BuildContext context) {
return RouterState(
notifier: _routerStateData,
child: MaterialApp.router(
routeInformationParser: _routeInformationParser,
routerDelegate: _routerDelegate,
),
);
}
#override
void dispose() {
_routerDelegate.dispose();
_routerStateData.dispose();
super.dispose();
}
#override
void initState() {
super.initState();
_routerDelegate = AppRouterDelegate(
routerStateData: _routerStateData,
);
}
}
/// https://api.flutter.dev/flutter/widgets/InheritedNotifier-class.html
class RouterState extends InheritedNotifier<RouterStateData> {
const RouterState({
Key? key,
RouterStateData? notifier,
required Widget child,
}) : super(
key: key,
notifier: notifier,
child: child,
);
static RouterStateData? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<RouterState>()?.notifier;
}
}
/// https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html
class RouterStateData extends ChangeNotifier {
/// The devotion day.
int? _devotionDay;
/// The devotion month.
int? _devotionMonth;
/// Gets the devotion day.
int? get devotionDay => _devotionDay;
/// Gets the devotion month.
int? get devotionMonth => _devotionMonth;
/// Updates the state of the router to a devotion day and a devotion month.
void setDevotionDayMonth(int? devotionDay, int? devotionMonth) {
_devotionDay = devotionDay;
_devotionMonth = devotionMonth;
notifyListeners();
}
}
/// A base route path that all route paths can extend from.
abstract class RoutePath {
const RoutePath();
}
/// The route path of the home.
class HomeRoutePath extends RoutePath {
const HomeRoutePath();
}
/// The route path of a devotion.
class DevotionRoutePath extends RoutePath {
/// The day of the devotion.
final int day;
/// The month of the devotion.
final int month;
const DevotionRoutePath({
required this.day,
required this.month,
});
}
/// https://api.flutter.dev/flutter/widgets/RouteInformationParser-class.html
class AppRouteInformationParser extends RouteInformationParser<RoutePath> {
#override
Future<RoutePath> parseRouteInformation(
RouteInformation routeInformation,
) async {
/// Gets the uri of the route, for example "/devotions/01-01".
final uri = Uri.parse(routeInformation.location!);
/// Switches on the number of path segments of the uri.
switch (uri.pathSegments.length) {
/// Cases on uris that have 2 path segments, for example "/devotions/1-1".
case 2:
/// Switches on the value of the first path segment of the uri.
switch (uri.pathSegments[0]) {
/// Cases on uris that start with devotions, for example "/devotions/1-1".
case 'devotions':
/// Gets the day and month dynamically from the uri.
final dayMonth = uri.pathSegments[1].split('-');
/// Returns the devotion route path with the day and month from the uri.
return SynchronousFuture(
DevotionRoutePath(
day: int.parse(dayMonth[0]),
month: int.parse(dayMonth[1]),
),
);
}
break;
}
/// Returns the default home route path if no other route paths match the uri.
return SynchronousFuture(HomeRoutePath());
}
#override
RouteInformation? restoreRouteInformation(
RoutePath configuration,
) {
/// If the current route path is home, then sets the uri to /.
if (configuration is HomeRoutePath) {
return RouteInformation(
location: '/',
);
/// If the current route path is devotion, then sets the uri to /devotions/day-month, for example "/devotions/1-1".
} else if (configuration is DevotionRoutePath) {
return RouteInformation(
location: '/devotions/${configuration.day}-${configuration.month}',
);
}
return null;
}
}
/// https://api.flutter.dev/flutter/widgets/RouterDelegate-class.html
class AppRouterDelegate extends RouterDelegate<RoutePath>
with ChangeNotifier, PopNavigatorRouterDelegateMixin<RoutePath> {
#override
final navigatorKey = GlobalKey<NavigatorState>();
final RouterStateData routerStateData;
AppRouterDelegate({
required this.routerStateData,
}) {
routerStateData.addListener(notifyListeners);
}
#override
RoutePath? get currentConfiguration {
final day = routerStateData.devotionDay;
final month = routerStateData.devotionMonth;
/// If both the day and the month are not null, then returns the route path for devotion; otherwise, returns the route path for home.
return day != null && month != null
? DevotionRoutePath(day: day, month: month)
: HomeRoutePath();
}
#override
Widget build(BuildContext context) {
final day = routerStateData.devotionDay;
final month = routerStateData.devotionMonth;
return Navigator(
key: navigatorKey,
pages: [
/// Pushes the home page onto the navigator stack.
const MaterialPage<void>(
child: HomePage(),
key: ValueKey('home_page'),
),
/// If both the day and the month are not null, then pushes the devotion page onto the navigator stack.
if (day != null && month != null)
MaterialPage<void>(
child: DevotionPage(
day: day,
month: month,
),
key: ValueKey('devotion_page'),
),
],
onPopPage: (route, result) {
if (!route.didPop(result)) {
return false;
}
/// If the devotion page is being popped, then clears the devotion day and devotion month from the router state.
routerStateData.setDevotionDayMonth(null, null);
return true;
},
);
}
#override
void dispose() {
routerStateData.removeListener(notifyListeners);
super.dispose();
}
#override
Future<void> setNewRoutePath(RoutePath configuration) async {
/// If the route path is home, then clears the devotion day and devotion month from the router state.
if (configuration is HomeRoutePath) {
routerStateData.setDevotionDayMonth(
null,
null,
);
/// If the route path is devotion, then sets the devotion day and devotion month in the router state.
} else if (configuration is DevotionRoutePath) {
routerStateData.setDevotionDayMonth(
configuration.day,
configuration.month,
);
}
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final _dayController = TextEditingController();
final _monthController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: ListView(
children: [
TextFormField(
controller: _dayController,
decoration: InputDecoration(
labelText: 'Day',
hintText: '01',
),
),
TextFormField(
controller: _monthController,
decoration: InputDecoration(
labelText: 'Month',
hintText: '01',
),
),
ElevatedButton(
onPressed: () {
/// Updates the router state with the entered devotion day and devotion month. This calls the `notifyListeners()` internally, which notifies the `AppRouterDelegate` that the route needs updating.
RouterState.of(context)?.setDevotionDayMonth(
int.parse(_dayController.text),
int.parse(_monthController.text),
);
},
child: Text('GO TO DEVOTION'),
),
],
),
);
}
#override
void dispose() {
_dayController.dispose();
_monthController.dispose();
super.dispose();
}
}
class DevotionPage extends StatelessWidget {
final int day;
final int month;
const DevotionPage({
Key? key,
required this.day,
required this.month,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Devotion'),
),
body: Center(
child: Text('$day-$month'),
),
);
}
}
Please note this is by no means the only solution and others can be found here and here.
If you have any questions, then please do let me know!
I need to show current date and month Also next 5 days date and month in a text widget.
Simply like this
Column(
children: [
Text('09'),
Text('Nov')
],
)
I need to show in a row that today date or month and the next 5 days date and month. Any guide in code how can i do this thing?
Expected output is
28NOV, 29NOV, 30NOV, 1Dec, 2Dec
A simple example. No styles applied, adjust to your needs.
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
class MyScreen extends StatefulWidget {
#override
_MyScreenState createState() => _MyScreenState();
}
class _MyScreenState extends State<MyScreen> {
final _currentDate = DateTime.now();
final _dayFormatter = DateFormat('d');
final _monthFormatter = DateFormat('MMM');
#override
Widget build(BuildContext context) {
final dates = <Widget>[];
for (int i = 0; i < 5; i++) {
final date = _currentDate.add(Duration(days: i));
dates.add(Column(
children: [
Text(_dayFormatter.format(date)),
Text(_monthFormatter.format(date)),
],
));
}
return Scaffold(
appBar: AppBar(
title: Text('Tests'),
),
body: Row(
children: dates.map((widget) => Expanded(child: widget)).toList(),
),
);
}
}
Also the default month names from the intl library are used.
You might need to adjust the code for i18n.
List months = ['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'];
DateTime today = DateTime.now();
var currentDate = today.day;
var monthOfCurrentDate = months[today.month +1];
DateTime futureDate = DateTime.now().add(Duration(days: 5));
var dayOfFutureDate = futureDate.day;
var monthOfFutureDate = months[futureDate.month+1];
You can use like this,
Column(
children: [
Text(currentDate.toString()),
Text(monthOfCurrentDate)
],
)
and you can format time as below, using flutter intl package intl package on pub.dev
DateFormat.MMMd().format(today) // this will output as "17 Nov"