chore: scroll activity dialog image with other content (#2860)
This commit is contained in:
parent
a5539b4bea
commit
8d5429771c
2 changed files with 346 additions and 312 deletions
|
|
@ -211,7 +211,7 @@ class ActivityPlannerBuilderState extends State<ActivityPlannerBuilder> {
|
|||
}
|
||||
|
||||
Future<void> clearEdits() async {
|
||||
_resetActivity();
|
||||
await _resetActivity();
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
isEditing = false;
|
||||
|
|
|
|||
|
|
@ -86,320 +86,350 @@ class ActivitySuggestionDialogState extends State<ActivitySuggestionDialog> {
|
|||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: _width,
|
||||
child: widget.controller.avatar != null
|
||||
? Image.memory(
|
||||
widget.controller.avatar!,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: widget.controller.updatedActivity.imageURL !=
|
||||
null
|
||||
? widget.controller.updatedActivity
|
||||
.imageURL!
|
||||
.startsWith("mxc")
|
||||
? MxcImage(
|
||||
uri: Uri.parse(
|
||||
widget.controller.updatedActivity
|
||||
.imageURL!,
|
||||
),
|
||||
width: _width,
|
||||
height: 200,
|
||||
cacheKey: widget.controller
|
||||
.updatedActivity.bookmarkId,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: CachedNetworkImage(
|
||||
imageUrl: widget.controller
|
||||
.updatedActivity.imageURL!,
|
||||
fit: BoxFit.cover,
|
||||
placeholder: (context, url) =>
|
||||
const Center(
|
||||
child:
|
||||
CircularProgressIndicator(),
|
||||
),
|
||||
errorWidget:
|
||||
(context, url, error) =>
|
||||
const SizedBox(),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
if (widget.controller.isEditing)
|
||||
Positioned(
|
||||
bottom: 8.0,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(90),
|
||||
onTap: widget.controller.selectAvatar,
|
||||
child: const CircleAvatar(
|
||||
radius: 24.0,
|
||||
child: Icon(
|
||||
Icons.add_a_photo_outlined,
|
||||
size: 24.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
spacing: 8.0,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (widget.controller.isEditing)
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Icons.event_note_outlined,
|
||||
child: TextFormField(
|
||||
controller:
|
||||
widget.controller.titleController,
|
||||
decoration: InputDecoration(
|
||||
labelText:
|
||||
L10n.of(context).activityTitle,
|
||||
),
|
||||
maxLines: 2,
|
||||
minLines: 1,
|
||||
),
|
||||
)
|
||||
else
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Icons.event_note_outlined,
|
||||
child: Text(
|
||||
widget.controller.updatedActivity.title,
|
||||
style:
|
||||
theme.textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
maxLines: 6,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
if (widget.controller.isEditing)
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Symbols.target,
|
||||
child: TextFormField(
|
||||
controller: widget.controller
|
||||
.learningObjectivesController,
|
||||
decoration: InputDecoration(
|
||||
labelText: L10n.of(context)
|
||||
.learningObjectiveLabel,
|
||||
),
|
||||
maxLines: 4,
|
||||
minLines: 1,
|
||||
),
|
||||
)
|
||||
else
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Symbols.target,
|
||||
child: Text(
|
||||
widget.controller.updatedActivity
|
||||
.learningObjective,
|
||||
maxLines: 6,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: theme.textTheme.bodyLarge,
|
||||
),
|
||||
),
|
||||
if (widget.controller.isEditing)
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Symbols.steps,
|
||||
child: TextFormField(
|
||||
controller: widget
|
||||
.controller.instructionsController,
|
||||
decoration: InputDecoration(
|
||||
labelText:
|
||||
L10n.of(context).instructions,
|
||||
),
|
||||
maxLines: 8,
|
||||
minLines: 1,
|
||||
),
|
||||
)
|
||||
else
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Symbols.steps,
|
||||
child: Text(
|
||||
widget.controller.updatedActivity
|
||||
.instructions,
|
||||
maxLines: 8,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: theme.textTheme.bodyLarge,
|
||||
),
|
||||
),
|
||||
if (widget.controller.isEditing)
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Icons.group_outlined,
|
||||
child: TextFormField(
|
||||
controller: widget
|
||||
.controller.participantsController,
|
||||
decoration: InputDecoration(
|
||||
labelText: L10n.of(context).classRoster,
|
||||
),
|
||||
maxLines: 1,
|
||||
keyboardType: TextInputType.number,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
final val = int.parse(value);
|
||||
if (val <= 0) {
|
||||
return L10n.of(context)
|
||||
.pleaseEnterInt;
|
||||
}
|
||||
} catch (e) {
|
||||
return L10n.of(context)
|
||||
.pleaseEnterANumber;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
)
|
||||
else
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Icons.group_outlined,
|
||||
child: Text(
|
||||
L10n.of(context).countParticipants(
|
||||
widget.controller.updatedActivity.req
|
||||
.numberOfParticipants,
|
||||
),
|
||||
style: theme.textTheme.bodyLarge,
|
||||
),
|
||||
),
|
||||
if (widget.controller.isEditing)
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Symbols.dictionary,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 60.0,
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Wrap(
|
||||
spacing: 4.0,
|
||||
runSpacing: 4.0,
|
||||
children: widget.controller.vocab
|
||||
.mapIndexed(
|
||||
(i, vocab) => Container(
|
||||
padding: const EdgeInsets
|
||||
.symmetric(
|
||||
vertical: 4.0,
|
||||
horizontal: 8.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: theme
|
||||
.colorScheme.primary
|
||||
.withAlpha(20),
|
||||
borderRadius:
|
||||
BorderRadius.circular(
|
||||
24.0,
|
||||
),
|
||||
),
|
||||
child: MouseRegion(
|
||||
cursor: SystemMouseCursors
|
||||
.click,
|
||||
child: GestureDetector(
|
||||
onTap: () => widget
|
||||
child: Column(
|
||||
spacing: 8.0,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: _width,
|
||||
child: widget.controller.avatar != null
|
||||
? Image.memory(
|
||||
widget.controller.avatar!,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: widget.controller.updatedActivity
|
||||
.imageURL !=
|
||||
null
|
||||
? widget.controller.updatedActivity
|
||||
.imageURL!
|
||||
.startsWith("mxc")
|
||||
? MxcImage(
|
||||
uri: Uri.parse(
|
||||
widget
|
||||
.controller
|
||||
.removeVocab(i),
|
||||
child: Row(
|
||||
spacing: 4.0,
|
||||
mainAxisSize:
|
||||
MainAxisSize.min,
|
||||
children: [
|
||||
Text(vocab.lemma),
|
||||
const Icon(
|
||||
Icons.close,
|
||||
size: 12.0,
|
||||
),
|
||||
],
|
||||
),
|
||||
.updatedActivity
|
||||
.imageURL!,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Symbols.dictionary,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 60.0,
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Wrap(
|
||||
spacing: 4.0,
|
||||
runSpacing: 4.0,
|
||||
children: widget.controller.vocab
|
||||
.map(
|
||||
(vocab) => Container(
|
||||
padding: const EdgeInsets
|
||||
.symmetric(
|
||||
vertical: 4.0,
|
||||
horizontal: 8.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: theme
|
||||
.colorScheme.primary
|
||||
.withAlpha(20),
|
||||
borderRadius:
|
||||
BorderRadius.circular(
|
||||
24.0,
|
||||
width: _width,
|
||||
height: 200,
|
||||
cacheKey: widget
|
||||
.controller
|
||||
.updatedActivity
|
||||
.bookmarkId,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: CachedNetworkImage(
|
||||
imageUrl: widget
|
||||
.controller
|
||||
.updatedActivity
|
||||
.imageURL!,
|
||||
fit: BoxFit.cover,
|
||||
placeholder:
|
||||
(context, url) =>
|
||||
const Center(
|
||||
child:
|
||||
CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
vocab.lemma,
|
||||
style: theme
|
||||
.textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
errorWidget: (
|
||||
context,
|
||||
url,
|
||||
error,
|
||||
) =>
|
||||
const SizedBox(),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
if (widget.controller.isEditing)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4.0,
|
||||
),
|
||||
child: Row(
|
||||
spacing: 4.0,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: widget
|
||||
.controller.vocabController,
|
||||
decoration: InputDecoration(
|
||||
hintText: L10n.of(context)
|
||||
.addVocabulary,
|
||||
),
|
||||
maxLines: 1,
|
||||
onFieldSubmitted: (_) =>
|
||||
widget.controller.addVocab(),
|
||||
if (widget.controller.isEditing)
|
||||
Positioned(
|
||||
bottom: 8.0,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(90),
|
||||
onTap: widget.controller.selectAvatar,
|
||||
child: const CircleAvatar(
|
||||
radius: 24.0,
|
||||
child: Icon(
|
||||
Icons.add_a_photo_outlined,
|
||||
size: 24.0,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
padding: const EdgeInsets.all(0.0),
|
||||
constraints:
|
||||
const BoxConstraints(), // override default min size of 48px
|
||||
iconSize: 16.0,
|
||||
icon: const Icon(Icons.add_outlined),
|
||||
onPressed: widget.controller.addVocab,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
if (widget.controller.isEditing)
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Icons.event_note_outlined,
|
||||
child: TextFormField(
|
||||
controller:
|
||||
widget.controller.titleController,
|
||||
decoration: InputDecoration(
|
||||
labelText:
|
||||
L10n.of(context).activityTitle,
|
||||
),
|
||||
maxLines: 2,
|
||||
minLines: 1,
|
||||
),
|
||||
)
|
||||
else
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Icons.event_note_outlined,
|
||||
child: Text(
|
||||
widget
|
||||
.controller.updatedActivity.title,
|
||||
style: theme.textTheme.titleLarge
|
||||
?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
maxLines: 6,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
if (widget.controller.isEditing)
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Symbols.target,
|
||||
child: TextFormField(
|
||||
controller: widget.controller
|
||||
.learningObjectivesController,
|
||||
decoration: InputDecoration(
|
||||
labelText: L10n.of(context)
|
||||
.learningObjectiveLabel,
|
||||
),
|
||||
maxLines: 4,
|
||||
minLines: 1,
|
||||
),
|
||||
)
|
||||
else
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Symbols.target,
|
||||
child: Text(
|
||||
widget.controller.updatedActivity
|
||||
.learningObjective,
|
||||
maxLines: 6,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: theme.textTheme.bodyLarge,
|
||||
),
|
||||
),
|
||||
if (widget.controller.isEditing)
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Symbols.steps,
|
||||
child: TextFormField(
|
||||
controller: widget.controller
|
||||
.instructionsController,
|
||||
decoration: InputDecoration(
|
||||
labelText:
|
||||
L10n.of(context).instructions,
|
||||
),
|
||||
maxLines: 8,
|
||||
minLines: 1,
|
||||
),
|
||||
)
|
||||
else
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Symbols.steps,
|
||||
child: Text(
|
||||
widget.controller.updatedActivity
|
||||
.instructions,
|
||||
maxLines: 8,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: theme.textTheme.bodyLarge,
|
||||
),
|
||||
),
|
||||
if (widget.controller.isEditing)
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Icons.group_outlined,
|
||||
child: TextFormField(
|
||||
controller: widget.controller
|
||||
.participantsController,
|
||||
decoration: InputDecoration(
|
||||
labelText:
|
||||
L10n.of(context).classRoster,
|
||||
),
|
||||
maxLines: 1,
|
||||
keyboardType: TextInputType.number,
|
||||
validator: (value) {
|
||||
if (value == null ||
|
||||
value.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
final val = int.parse(value);
|
||||
if (val <= 0) {
|
||||
return L10n.of(context)
|
||||
.pleaseEnterInt;
|
||||
}
|
||||
} catch (e) {
|
||||
return L10n.of(context)
|
||||
.pleaseEnterANumber;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
)
|
||||
else
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Icons.group_outlined,
|
||||
child: Text(
|
||||
L10n.of(context).countParticipants(
|
||||
widget.controller.updatedActivity
|
||||
.req.numberOfParticipants,
|
||||
),
|
||||
style: theme.textTheme.bodyLarge,
|
||||
),
|
||||
),
|
||||
if (widget.controller.isEditing)
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Symbols.dictionary,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 60.0,
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Wrap(
|
||||
spacing: 4.0,
|
||||
runSpacing: 4.0,
|
||||
children: widget.controller.vocab
|
||||
.mapIndexed(
|
||||
(i, vocab) => Container(
|
||||
padding: const EdgeInsets
|
||||
.symmetric(
|
||||
vertical: 4.0,
|
||||
horizontal: 8.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: theme
|
||||
.colorScheme.primary
|
||||
.withAlpha(20),
|
||||
borderRadius:
|
||||
BorderRadius
|
||||
.circular(
|
||||
24.0,
|
||||
),
|
||||
),
|
||||
child: MouseRegion(
|
||||
cursor:
|
||||
SystemMouseCursors
|
||||
.click,
|
||||
child: GestureDetector(
|
||||
onTap: () => widget
|
||||
.controller
|
||||
.removeVocab(i),
|
||||
child: Row(
|
||||
spacing: 4.0,
|
||||
mainAxisSize:
|
||||
MainAxisSize
|
||||
.min,
|
||||
children: [
|
||||
Text(vocab.lemma),
|
||||
const Icon(
|
||||
Icons.close,
|
||||
size: 12.0,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
ActivitySuggestionCardRow(
|
||||
icon: Symbols.dictionary,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 60.0,
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Wrap(
|
||||
spacing: 4.0,
|
||||
runSpacing: 4.0,
|
||||
children: widget.controller.vocab
|
||||
.map(
|
||||
(vocab) => Container(
|
||||
padding: const EdgeInsets
|
||||
.symmetric(
|
||||
vertical: 4.0,
|
||||
horizontal: 8.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: theme
|
||||
.colorScheme.primary
|
||||
.withAlpha(20),
|
||||
borderRadius:
|
||||
BorderRadius
|
||||
.circular(
|
||||
24.0,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
vocab.lemma,
|
||||
style: theme.textTheme
|
||||
.bodyMedium,
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.controller.isEditing)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4.0,
|
||||
),
|
||||
child: Row(
|
||||
spacing: 4.0,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: widget
|
||||
.controller.vocabController,
|
||||
decoration: InputDecoration(
|
||||
hintText: L10n.of(context)
|
||||
.addVocabulary,
|
||||
),
|
||||
maxLines: 1,
|
||||
onFieldSubmitted: (_) => widget
|
||||
.controller
|
||||
.addVocab(),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
padding:
|
||||
const EdgeInsets.all(0.0),
|
||||
constraints:
|
||||
const BoxConstraints(), // override default min size of 48px
|
||||
iconSize: 16.0,
|
||||
icon: const Icon(
|
||||
Icons.add_outlined,
|
||||
),
|
||||
onPressed:
|
||||
widget.controller.addVocab,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -459,13 +489,17 @@ class ActivitySuggestionDialogState extends State<ActivitySuggestionDialog> {
|
|||
),
|
||||
),
|
||||
if (widget.controller.isEditing)
|
||||
GestureDetector(
|
||||
child: const Icon(
|
||||
Icons.close_outlined,
|
||||
size: 16.0,
|
||||
IconButton.filled(
|
||||
style: IconButton.styleFrom(
|
||||
backgroundColor: theme.colorScheme.primary,
|
||||
),
|
||||
onTap: () {
|
||||
widget.controller.clearEdits();
|
||||
padding: const EdgeInsets.all(6.0),
|
||||
constraints:
|
||||
const BoxConstraints(), // override default min size of 48px
|
||||
iconSize: 24.0,
|
||||
icon: const Icon(Icons.close_outlined),
|
||||
onPressed: () async {
|
||||
await widget.controller.clearEdits();
|
||||
widget.controller.setEditing(false);
|
||||
},
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue