I have an app I am working on. I used sharedpreferences and provider to store the index of the pageview of the screen so that when I click on a button from the home page, it navigates to the PageViewScreen and will continue from the last index page of the pageView screen I was before leaving the app. However I want to make the app to start from the first index if the date changes to another date.
To explain further, If user opens the app 28th of January in the morning, I would love to store the last page index they were on before leaving the app. If user then come back in the afternoon, I would want that they continue from where they stop. However if the time changes to 29th of January from exactly 12am, I want to clear the data saved in sharedpreferences so that they can start from first index.
I understand that I will use sharedpreference clear or remove method but I do not understand how to track each day so I can use the method.
I have created the code to save the last index but remains how to clear the last index for every date change.
here is my provider and shared preference file
import 'package:flutter/cupertino.dart';
import 'package:shared_preferences/shared_preferences.dart';
class ProviderData extends ChangeNotifier {
SharedPreferences? prefs;
final String pageIndexKey = 'pageIndex';
int? _pageIndex;
ProviderData() {
_pageIndex = 0;
loadFromPrefs();
}
_initPrefs() async {
prefs ??= await SharedPreferences.getInstance();
}
loadFromPrefs() async {
await _initPrefs();
_pageIndex = prefs!.getInt(pageIndexKey) ?? 0;
notifyListeners();
return _pageIndex;
}
_savePageIndexToPrefs({required String key, required int value}) async {
await _initPrefs();
prefs!.setInt(key, value);
}
void changePageIndex(int newPageIndex) {
_pageIndex = newPageIndex;
_savePageIndexToPrefs(key: pageIndexKey, value: _pageIndex!);
notifyListeners();
}
}
below is my PageViewScreen file,
I use Future builder to get my last index so I can build my app based on the last index
Future getProvider() {
return ProviderData().loadFromPrefs().then((value) {
return PageController(initialPage: value - 1);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: getProvider(),
builder: ((context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return Center(
child: Text(
'${snapshot.error} occurred',
style: TextStyle(fontSize: 18),
));
} else if (snapshot.hasData) {
final control = snapshot.data;
return Stack(
children: [
Consumer<ProviderData>(
builder: (context, providerData, _) {
return PageView(
controller: control,
onPageChanged: (index) {
///// I saved the index of the pageview here but I would love to clear it and make it start from index1 for every new date i.e 12am of everyday.
providerData.changePageIndex(index);
// setState(() {
// onLastPage = index == 2;
// onFirstPage = index == 0;
// onSecondPage = index == 1;
// onThirdPage = index == 2;
// onFourthPage = index == 3;
// onFifthPage = index == 4;
// onSixthPage = index == 5;
// onSeventhPage = index == 6;
// });
},
children: _pageList,
);
},
),
Align(
alignment: Alignment(0, -0.8),
child: Consumer<ProviderData>(
builder: (context, providerData, _) {
return SmoothPageIndicator(
controller: control,
count: 13,
effect: SlideEffect(
activeDotColor: Color.fromRGBO(215, 60, 16, 1)),
);
}),
),
Align(
alignment: Alignment(0, 0.5),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
GestureDetector(
onTap: (() {
control.previousPage(
duration: Duration(milliseconds: 500),
curve: Curves.easeIn);
}),
child: Text(
"prev",
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 16),
),
),
GestureDetector(
onTap: (() {
control.nextPage(
curve: Curves.easeIn,
duration: Duration(milliseconds: 500));
}),
child: Text(
"Next",
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 16),
),
),
],
),
)
],
);
}
}
return Center(child: CircularProgressIndicator());
}
)
)
);
}
Please I need someone that can help me solve and approach this issue.
Thank you in advance
You can keep the date of last change inside the Shared Preferences, and to check it every time when you load the preferences. It's important to keep the date without time and minutes, so recreating the date during the same day will have the same value.
You can simplify the provider logic and only use it as Provider instead of ChangeNotifier.
Here is a working example:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final sharedPrefs = await SharedPreferences.getInstance();
runApp(
Provider(
create: (context) => ProviderData(sharedPrefs),
child: const MainApp(),
),
);
}
class MainApp extends StatefulWidget {
const MainApp({super.key});
@override
State<MainApp> createState() => _MainAppState();
}
class _MainAppState extends State<MainApp> {
final _pages = [
const Center(
child: Text(
'Page 1',
style: TextStyle(fontSize: 38),
),
),
const Center(
child: Text(
'Page 2',
style: TextStyle(fontSize: 38),
),
),
const Center(
child: Text(
'Page 3',
style: TextStyle(fontSize: 38),
),
),
const Center(
child: Text(
'Page 4',
style: TextStyle(fontSize: 38),
),
),
];
late final PageController _pageController;
late final ProviderData _providerData;
bool loading = true;
@override
void initState() {
WidgetsBinding.instance.scheduleFrameCallback((timeStamp) {
_providerData = context.read<ProviderData>();
_pageController = PageController(initialPage: _providerData.getPageIndex());
setState(() => loading = false);
});
super.initState();
}
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: loading
? const Center(child: CircularProgressIndicator())
: Scaffold(
body: Stack(
children: [
PageView(
controller: _pageController,
children: _pages,
onPageChanged: (value) => _providerData.savePageIndexToPrefs(value: value),
),
Align(
alignment: const Alignment(0, -0.8),
child: SmoothPageIndicator(
controller: _pageController,
count: _pages.length,
effect: const SlideEffect(activeDotColor: Color.fromRGBO(215, 60, 16, 1)),
),
),
Align(
alignment: const Alignment(0, 0.5),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
GestureDetector(
onTap: (() {
_pageController.previousPage(duration: const Duration(milliseconds: 500), curve: Curves.easeIn);
}),
child: const Text(
"Prev",
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 16),
),
),
GestureDetector(
onTap: (() {
_pageController.nextPage(curve: Curves.easeIn, duration: const Duration(milliseconds: 500));
}),
child: const Text(
"Next",
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 16),
),
),
],
),
)
],
),
),
);
}
}
class ProviderData {
ProviderData(this._prefs);
final SharedPreferences _prefs;
static const String _pageIndexKey = 'pageIndex';
static const String _pageIndexLastUpdated = 'pageIndexLastUpdatedKey';
int getPageIndex() {
final lastUpdatedStr = _prefs.getString(_pageIndexLastUpdated);
if (lastUpdatedStr != null) {
final lastUpdated = DateTime.parse(lastUpdatedStr);
final now = DateTime.now();
// creating a date without hours and minutes
final today = DateTime.utc(now.year, now.month, now.day);
if (lastUpdated.isAtSameMomentAs(today)) {
final pageIndex = _prefs.getInt(_pageIndexKey) ?? 0;
return pageIndex;
}
}
_prefs.remove(_pageIndexKey);
return 0;
}
void savePageIndexToPrefs({required int value}) {
_prefs.setInt(_pageIndexKey, value);
final now = DateTime.now();
// creating a date without hours and minutes
final today = DateTime.utc(now.year, now.month, now.day);
_prefs.setString(_pageIndexLastUpdated, today.toIso8601String());
}
}