I tried to create a button in the AppBar that displays a PopUpMenu if you press it. In the PopUpMenu there schould be several boxes with text next to them that you can check.
I tried creating a column in which I first display a title and then a CheckBoxListTile, but I couldn’t check the CheckBox.
This is my code:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:mynotes/constants/routes.dart';
import 'package:mynotes/enums/menu_action.dart';
import 'package:mynotes/extensions/buildcontext/loc.dart';
import 'package:mynotes/services/auth/auth_service.dart';
import 'package:mynotes/services/auth/bloc/auth_bloc.dart';
import 'package:mynotes/services/auth/bloc/auth_event.dart';
import 'package:mynotes/services/cloud/cloud_note.dart';
import 'package:mynotes/services/cloud/firebase_cloud_storage.dart';
import 'package:mynotes/utilities/dialogs/logout_dialog.dart';
import 'package:mynotes/views/notes/notes_list_view.dart';
import 'package:flutter_bloc/flutter_bloc.dart' show ReadContext;
extension Count<T extends Iterable> on Stream<T> {
Stream<int> get getLength => map((event) => event.length);
}
class NotesView extends StatefulWidget {
const NotesView({Key? key}) : super(key: key);
@override
_NotesViewState createState() => _NotesViewState();
}
class _NotesViewState extends State<NotesView> {
late final FirebaseCloudStorage _notesService;
String get userId => AuthService.firebase().currentUser!.id;
bool isInputVisible = false;
TextEditingController _textEditingController = TextEditingController();
String searchResult = 'Nachhilfe';
late final RawKeyboard _rawKeyboard;
List<String> selectedFilters = [];
late bool? isChecked1;
@override
void initState() {
_notesService = FirebaseCloudStorage();
_textEditingController = TextEditingController();
_setupTextControllerListener();
_rawKeyboard = RawKeyboard.instance;
_rawKeyboard.addListener(_onKeyEvent);
isChecked1 = false;
super.initState();
}
void _textControllerListener() async {
final suche = _textEditingController.text;
}
void _onKeyEvent(RawKeyEvent event) {
if (event is RawKeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.enter) {
searchResult = _textEditingController.text;
setState(() {
isInputVisible = false;
});
print(searchResult);
}
}
void _setupTextControllerListener() {
_textEditingController.removeListener(_textControllerListener);
_textEditingController.addListener(_textControllerListener);
}
@override
void dispose() {
_textEditingController.dispose();
_rawKeyboard.removeListener(_onKeyEvent);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: StreamBuilder(
stream: _notesService.allNotes(searchResult).getLength,
builder: (context, AsyncSnapshot<int> snapshot) {
if (snapshot.hasData) {
final noteCount = snapshot.data ?? 0;
final text = context.loc.notes_title(noteCount);
return Text(text);
} else {
return const Text('');
}
},
),
actions: [
PopupMenuButton<int>(
icon: Icon(Icons.filter_list),
itemBuilder: (BuildContext context) {
return <PopupMenuEntry<int>>[
PopupMenuItem<int>(
value: 0,
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 8.0, horizontal: 12.0),
child: Column(
children: [
const Text(
'Select Filters',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0,
),
),
CheckboxListTile(
title: const Text('Bogenhausen'),
controlAffinity: ListTileControlAffinity.leading,
value: isChecked1,
onChanged: (bool? newValue) {
setState(() {
isChecked1 = newValue;
});
},
activeColor: Colors.greenAccent,
checkColor: Colors.black,
),
],
)),
),
];
},
),
IconButton(
icon: const Icon(Icons.search),
onPressed: () {
setState(() {
isInputVisible = !isInputVisible;
});
},
),
Visibility(
visible: isInputVisible,
child: Container(
width: 200,
child: Padding(
padding: const EdgeInsets.all(5.0),
child: TextField(
controller: _textEditingController,
decoration: const InputDecoration(
hintText: 'search',
border: OutlineInputBorder(),
),
),
),
),
),
IconButton(
onPressed: () {
Navigator.of(context).pushNamed(createOrUpdateNoteRoute);
},
icon: const Icon(Icons.add),
),
PopupMenuButton<MenuAction>(
onSelected: (value) async {
switch (value) {
case MenuAction.logout:
final shouldLogout = await showLogOutDialog(context);
if (shouldLogout) {
context.read<AuthBloc>().add(
const AuthEventLogOut(),
);
}
}
},
itemBuilder: (context) {
return [
PopupMenuItem<MenuAction>(
value: MenuAction.logout,
child: Text(context.loc.logout_button),
),
];
},
)
],
),
body: StreamBuilder(
stream: _notesService.allNotes(searchResult),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
case ConnectionState.active:
if (snapshot.hasData) {
final allNotes = snapshot.data as Iterable<CloudNote>;
final sortedNotes = sortNotes(allNotes, searchResult);
return NotesListView(
notes: sortedNotes,
onDeleteNote: (note) async {
await _notesService.deleteNote(documentId: note.documentId);
},
onTap: (note) {
Navigator.of(context).pushNamed(
showNotesRoute,
arguments: note.documentId,
);
},
);
} else {
return const CircularProgressIndicator();
}
default:
return const CircularProgressIndicator();
}
},
),
);
}
}
Iterable<CloudNote> sortNotes(Iterable<CloudNote> notes, String searchResult) {
final List<CloudNote> specificValueNotes = [];
final List<CloudNote> otherNotes = [];
final hi = searchResult;
for (final note in notes) {
if (note.textJob == hi || note.textJob == 'Nachhilfe') {
specificValueNotes.add(note);
} else {
otherNotes.add(note);
}
}
return [...specificValueNotes, ...otherNotes];
}
List<String> selectedFilters = [];
void _handleFilterSelection(String filter) {
if (selectedFilters.contains(filter)) {
selectedFilters.remove(filter);
} else {
selectedFilters.add(filter);
}
}
2
Answers
To ensure that the
PopupMenuItem
gets refreshed, you need to wrap it with aStatefulBuilder
.Here’s how you can do it:
To update the states of both _NotesViewState and the
PopupMenuItem
, you’ll need to call setState for each specific context.