I am a Flutter begginer.
I make Trash Day Manage application.it is kind of similler to TODO application.
DB is Hive. State management is RiverPod and CahngeNotifier.
https://github.com/dai10512/trash-out/tree/master
problem is happen in detail page.
edithing data could not reset and still kept.
original data is from hive. And then load Instance as TrashDay. TrashDay is also created from TrashDay.
In my hope, when save(保存) button is pushed, add or update TrashDayModel to hive. but hive and TrashDay parameter is also Changed uncontiouslly.
How Can I reset edithing data to pop page? Any idea Please.
movie. after hot reload it looks changed but hive data is still same
Data Change
|state | loaded or default TrashDay | TrashDayModel|
|---- | -------- |-----------------|--------------|
|hope | No | Yes | |
|real | Yes | Yes | |
code is below
///detaile_view
import 'package:flutter/material.dart';
import 'package:trash_out/model/trashDayList_model.dart';
import 'package:trash_out/model/trashDay_model.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class TrashDetailView extends ConsumerWidget {
const TrashDetailView(this.hiveKey, {Key? key}) : super(key: key);
final dynamic hiveKey;
@override
Widget build(context, ref) {
// final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
final TrashDayListModel trashDayListRead = ref.read(trashDayListModelProvider);
final TrashDayModel trashDayRead = ref.read(trashDayModelProvider);
final dynamic loadedTrashDay = trashDayListRead.loadTrashDay(hiveKey);
trashDayRead.loadData(loadedTrashDay);
return Scaffold(
// key: scaffoldKey,
appBar: AppBar(
automaticallyImplyLeading: true,
title: const Text('Page Title'),
centerTitle: true,
),
body: SafeArea(
child: SingleChildScrollView(
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Padding(
padding: const EdgeInsetsDirectional.fromSTEB(20, 20, 20, 20),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_trashTypeForm(),
_notificationDateForm(),
_finishButton(hiveKey, trashDayRead),
Text('ordinalNumbers'),
Text(ref.watch(trashDayModelProvider).ordinalNumbers.toString()),
TextButton(
onPressed: () {
trashDayRead.reset();
},
child: Text('reset'),
),
],
),
),
),
),
),
);
}
Widget _trashTypeForm() {
return Consumer(
builder: (context, ref, _) {
final TrashDayModel trashDayRead = ref.read(trashDayModelProvider);
final controller = TextEditingController(text: trashDayRead.trashType);
return Column(
children: [
Card(
clipBehavior: Clip.antiAliasWithSaveLayer,
color: const Color(0xFFF5F5F5),
child: Padding(
padding: const EdgeInsetsDirectional.fromSTEB(15, 15, 15, 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('ゴミの種類'),
const SizedBox(height: 10),
TextFormField(
controller: controller,
autofocus: true,
obscureText: false,
decoration: const InputDecoration(hintText: '[例:燃えるゴミ]', filled: true),
onChanged: (text) {
print(text);
trashDayRead.updateTrashType(text);
},
),
],
),
),
),
],
);
},
);
}
Widget _notificationDateForm() {
return Card(
clipBehavior: Clip.antiAliasWithSaveLayer,
color: const Color(0xFFF5F5F5),
child: Padding(
padding: const EdgeInsetsDirectional.fromSTEB(15, 15, 15, 15),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_ordinalNumberCheck(),
const SizedBox(width: 20),
_dayOfTheWeekCheck(),
],
),
),
);
}
}
Widget _ordinalNumberCheck() {
return Consumer(
builder: (context, ref, _) {
final TrashDayModel trashDayRead = ref.read(trashDayModelProvider);
final TrashDayModel trashDayWatch = ref.watch(trashDayModelProvider);
return Expanded(
flex: 2,
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'第◯番目',
textAlign: TextAlign.center,
),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: trashDayWatch.ordinalNumbers.length,
itemBuilder: (BuildContext context, int index) {
return ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
(trashDayWatch.ordinalNumbers[index + 1]!) ? Colors.blue : Colors.grey,
),
),
onPressed: () {
trashDayRead.updateOrdinalNumbers(index + 1);
},
child: Text('第${index + 1}'),
);
},
),
],
),
);
},
);
}
Widget _dayOfTheWeekCheck() {
return Consumer(
builder: (context, ref, _) {
final TrashDayModel trashDayRead = ref.read(trashDayModelProvider);
final TrashDayModel trashDayWatch = ref.watch(trashDayModelProvider);
return Expanded(
flex: 3,
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'曜日',
textAlign: TextAlign.center,
),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: trashDayRead.daysOfTheWeek.length,
itemBuilder: (BuildContext context, int index) {
return ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
(trashDayWatch.daysOfTheWeek[index + 1]!) ? Colors.blue : Colors.grey,
),
),
onPressed: () {
trashDayRead.updateDaysOfTheWeek(index + 1);
},
child: Text(dayOfTheWeekLabelMap[index + 1].toString()),
);
},
),
],
),
);
},
);
}
Widget _finishButton(dynamic hiveKey, TrashDayModel trashDayRead) {
return Consumer(
builder: (context, ref, child) {
final trashDayListModel = ref.read(trashDayListModelProvider);
return SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.orange,
onPrimary: Colors.white,
),
onPressed: () async {
if (hiveKey == null) {
trashDayListModel.addTrashDay(trashDayRead);
Navigator.pop(context);
} else {
trashDayListModel.updateTrashDay(hiveKey, trashDayRead);
Navigator.pop(context);
}
},
child: const Text('保存する'),
),
);
},
);
}
final dayOfTheWeekLabelMap = {
1: '月曜日',
2: '火曜日',
3: '水曜日',
4: '木曜日',
5: '金曜日',
6: '土曜日',
7: '日曜日',
};
///TrashDayModel
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:trash_out/typeAdapter/trashDay.dart';
import 'package:uuid/uuid.dart';
final trashDayModelProvider = ChangeNotifierProvider<TrashDayModel>(
(ref) => TrashDayModel(),
);
Uuid uuid = const Uuid();
final defaultTrashDay = TrashDay(
id: uuid.v4(),
trashType: '',
daysOfTheWeek: {1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false},
ordinalNumbers: {1: false, 2: false, 3: false, 4: false, 5: false},
);
class TrashDayModel extends ChangeNotifier {
String id = '';
String trashType = '';
Map<int, bool> daysOfTheWeek = {};
Map<int, bool> ordinalNumbers = {};
// listから選んだ場合は、DBのkeyからloadedTrashDayを引数に。ない場合に上記DefaultTrashDayの値をModelのパラメーターに充てて更新している。
// 詳細ページに移る時は常にこれらが呼び出されて、フレッシュなデータになる想定である。
// しかし、実際のところは、loadedTrashDayやdefaultTrashDayの中身ごと更新されてしまっている。
void loadData(TrashDay? loadedTrashDay) {
final TrashDay model;
if (loadedTrashDay != null) {
model = loadedTrashDay;
print('load form hive');
print(loadedTrashDay.ordinalNumbers);
} else {
model = defaultTrashDay;
print('load from defaultTrashDay');
print(defaultTrashDay.ordinalNumbers);
}
id = model.id;
trashType = model.trashType;
daysOfTheWeek = model.daysOfTheWeek;
ordinalNumbers = model.ordinalNumbers;
print('loaded');
}
void reset() {
id = uuid.v4();
trashType = '';
daysOfTheWeek = {1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false};
ordinalNumbers = {1: false, 2: false, 3: false, 4: false, 5: false};
print('reset');
print(ordinalNumbers);
// notifyListeners();
}
// こちらはビルドするタイミングなのでnotifyLisnerは不要とのこと
void updateTrashType(String text) {
trashType = text;
notifyListeners();
// controllerで反映されるからnotifyLisnerは不要と思われる
}
void updateDaysOfTheWeek(int index) {
daysOfTheWeek[index] = !daysOfTheWeek[index]!;
notifyListeners();
}
void updateOrdinalNumbers(int index) {
ordinalNumbers[index] = !ordinalNumbers[index]!;
notifyListeners();
}
}