I have an array of Character objects that is handled by a Provider and set through an SQL query. When I perform an INSERT action the new Character is successfully added to the pageview. But when I perform a DELETE action and remove the Character from the pageview, it removes it from the list but doesn't update the UI to display the next character in the array - it continues to show the deleted character's information until forced to rebuild by navigating away and back. I know that it is successfully being removed from the database and the array because my page indicator is reduced by 1. The current Character is handled by another provider and set by passing it into the CharacterState notifier as a parameter.
What I want is for the CharacterState to display the info from the next character in the array after a DELETE action is performed. I believe the issue is how the Character object is passed from CharacterListState to CharacterState. It works properly when the user swipes between pages or DELETEs the last item in the array, but otherwise the CharacterState just keeps displaying the old information until the whole state is rebuilt manually by leaving the page and coming back.
Please find the relevant code below:
class CharacterListPage extends StatefulWidget {
@override
_CharacterListPageState createState() => _CharacterListPageState();
}
class _CharacterListPageState extends State<CharacterListPage> {
PageController _pageController = PageController();
@override
Widget build(BuildContext context) {
final AppState appState = Provider.of<AppState>(context);
final CharacterListState characterListState =
Provider.of<CharacterListState>(context);
// _pageController.jumpToPage(appState.position);
return Scaffold(
resizeToAvoidBottomPadding: true,
body: FutureBuilder<bool>(
future: characterListState.setCharacterList(),
builder: (context, AsyncSnapshot<bool> _snapshot) {
return _snapshot.hasError
? Container(child: Text(_snapshot.error.toString()))
: !_snapshot.hasData
? Container(
child: Center(child: CircularProgressIndicator()),
height: MediaQuery.of(context).size.height,
)
: PageIndicatorContainer(
child: PageView.builder(
controller: _pageController =
PageController(initialPage: appState.position),
onPageChanged: (_index) async {
var prefs = await SharedPreferences.getInstance();
appState.position = _index;
prefs.setInt('position', _index);
appState.setTheme(characterListState
.characterList[_index].classColor);
prefs.setString(
'themeColor',
characterListState
.characterList[_index].classColor);
},
itemCount: characterListState.characterList.length,
itemBuilder: (BuildContext context, int index) {
return Container(
padding: EdgeInsets.all(smallPadding),
child: Card(
child: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.9),
image: DecorationImage(
image: AssetImage(
'images/class_icons/${characterListState.characterList[index].classIcon}'),
colorFilter: ColorFilter.mode(
Colors.white.withOpacity(0.9),
BlendMode.lighten),
),
),
),
Container(
color: Color(int.parse(
characterListState
.characterList[index]
.classColor))
.withOpacity(0.2)),
SingleChildScrollView(
child: ChangeNotifierProvider<
CharacterState>(
builder: (context) => CharacterState(
characterListState
.characterList[index].id,
),
child: Container(
padding: EdgeInsets.all(smallPadding),
child: CharacterPage(),
),
),
)
],
),
),
);
},
),
align: IndicatorAlign.top,
length: characterListState.characterList.length,
indicatorSpace: smallPadding,
padding: const EdgeInsets.only(top: 20),
indicatorColor: Colors.white,
indicatorSelectorColor: appState.accentColor,
shape: IndicatorShape.circle(size: 12),
);
// shape: IndicatorShape.roundRectangleShape(size: Size.square(12),cornerSize: Size.square(3)),
// shape: IndicatorShape.oval(size: Size(12, 8)),
}),
floatingActionButton: SpeedDial(
animatedIcon: AnimatedIcons.menu_close,
animatedIconTheme: IconThemeData(size: 22.0),
closeManually: false,
curve: Curves.bounceIn,
overlayColor: Colors.black,
overlayOpacity: 0.5,
elevation: 8.0,
shape: CircleBorder(),
children: [
SpeedDialChild(
child: Icon(Icons.add),
backgroundColor: Theme.of(context).accentColor,
label: 'Import Legacy Character',
labelStyle: TextStyle(fontSize: 18.0),
onTap: () async => await characterListState.addLegacyCharacter()),
SpeedDialChild(
child: Icon(Icons.add),
backgroundColor: Colors.green,
label: 'Add New Character',
labelStyle: TextStyle(fontSize: 18.0),
onTap: () async {
await showDialog(
context: context,
builder: (BuildContext context) {
return NewCharacterDialog(characterListState: characterListState);
},
);
_pageController
.jumpToPage(characterListState.characterList.length + 1);
},
),
SpeedDialChild(
child: Icon(Icons.add),
backgroundColor: Colors.green,
label: 'OPEN OLD CHAR SHEET',
labelStyle: TextStyle(fontSize: 18.0),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CharacterSheetPage()),
);
})
],
),
);
}
}
CharacterListState class
class CharacterListState with ChangeNotifier {
List<Character> _characterList = [];
List<bool> _legacyPerks = [];
DatabaseHelper db = DatabaseHelper.instance;
List<Character> get characterList => _characterList;
Future<bool> setCharacterList() async {
// List _list = [];
_characterList = await db.queryAllCharacters();
// _list.forEach((_result) => _result.))
// await db.queryPlayerClass(_classCode)
return true;
}
Future addCharacter(String _name, PlayerClass _playerClass) async {
Character _character = Character();
List<bool> _perks = [];
perkList.forEach((_perk) {
for (var x = 0; x < _perk.numOfPerks; x++) {
_perks.add(false);
}
});
_character.name = _name;
// _character.playerClass = _playerClass;
_character.classCode = _playerClass.classCode;
_character.classColor = _playerClass.classColor;
_character.classIcon = _playerClass.classIconUrl;
_character.classRace = _playerClass.race;
_character.className = _playerClass.className;
_character.xp = 0;
_character.gold = 0;
_character.notes = 'Add notes here';
_character.checkMarks = 0;
_character.isRetired = false;
int id = await db.insertCharacter(_character, _perks);
_character.id = id;
print('inserted row: $id');
print(_character.name);
print(_character.classCode);
notifyListeners();
}
Future deleteCharacter(int _characterId) async {
await db.deleteCharacter(_characterId);
// _characterList.removeWhere((value) => value.id == _characterId);
notifyListeners();
}
}