✨ Poll collapse
This commit is contained in:
@@ -133,6 +133,25 @@
|
|||||||
"other": "{} replies"
|
"other": "{} replies"
|
||||||
},
|
},
|
||||||
"forward": "Forward",
|
"forward": "Forward",
|
||||||
|
"award": "Award",
|
||||||
|
"awardPost": "Award Post",
|
||||||
|
"awardMessage": "Message",
|
||||||
|
"awardMessageHint": "Enter your award message...",
|
||||||
|
"awardAttitude": "Attitude",
|
||||||
|
"awardAttitudePositive": "Positive",
|
||||||
|
"awardAttitudeNegative": "Negative",
|
||||||
|
"awardAmount": "Amount",
|
||||||
|
"awardAmountHint": "Enter amount...",
|
||||||
|
"awardAmountRequired": "Amount is required",
|
||||||
|
"awardAmountInvalid": "Please enter a valid amount",
|
||||||
|
"awardMessageTooLong": "Message is too long (max 4096 characters)",
|
||||||
|
"awardSuccess": "Award sent successfully!",
|
||||||
|
"awardSubmit": "Award",
|
||||||
|
"awardPostPreview": "Post Preview",
|
||||||
|
"awardNoContent": "No content available",
|
||||||
|
"awardByPublisher": "By {}",
|
||||||
|
"awardBenefits": "Award Benefits",
|
||||||
|
"awardBenefitsDescription": "Awarding this post increases its value and visibility. Higher valued posts have a better chance of being featured and highlighted in the community.",
|
||||||
"repliedTo": "Replied to",
|
"repliedTo": "Replied to",
|
||||||
"forwarded": "Forwarded",
|
"forwarded": "Forwarded",
|
||||||
"hasAttachments": {
|
"hasAttachments": {
|
||||||
@@ -977,5 +996,7 @@
|
|||||||
"pinned": "Pinned",
|
"pinned": "Pinned",
|
||||||
"noResultsFound": "No results found",
|
"noResultsFound": "No results found",
|
||||||
"toggleFilters": "Toggle filters",
|
"toggleFilters": "Toggle filters",
|
||||||
"notableDayNext": "{} is in"
|
"notableDayNext": "{} is in",
|
||||||
|
"expandPoll": "Expand Poll",
|
||||||
|
"collapsePoll": "Collapse Poll"
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@ class PollSubmit extends ConsumerStatefulWidget {
|
|||||||
this.onCancel,
|
this.onCancel,
|
||||||
this.showProgress = true,
|
this.showProgress = true,
|
||||||
this.isReadonly = false,
|
this.isReadonly = false,
|
||||||
|
this.isInitiallyExpanded = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
final SnPollWithStats poll;
|
final SnPollWithStats poll;
|
||||||
@@ -36,6 +37,9 @@ class PollSubmit extends ConsumerStatefulWidget {
|
|||||||
|
|
||||||
final bool isReadonly;
|
final bool isReadonly;
|
||||||
|
|
||||||
|
/// Whether the poll should start expanded instead of collapsed.
|
||||||
|
final bool isInitiallyExpanded;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ConsumerState<PollSubmit> createState() => _PollSubmitState();
|
ConsumerState<PollSubmit> createState() => _PollSubmitState();
|
||||||
}
|
}
|
||||||
@@ -45,6 +49,7 @@ class _PollSubmitState extends ConsumerState<PollSubmit> {
|
|||||||
int _index = 0;
|
int _index = 0;
|
||||||
bool _submitting = false;
|
bool _submitting = false;
|
||||||
bool _isModifying = false; // New state to track if user is modifying answers
|
bool _isModifying = false; // New state to track if user is modifying answers
|
||||||
|
bool _isCollapsed = true; // New state to track collapse/expand
|
||||||
|
|
||||||
/// Collected answers, keyed by questionId
|
/// Collected answers, keyed by questionId
|
||||||
late Map<String, dynamic> _answers;
|
late Map<String, dynamic> _answers;
|
||||||
@@ -65,6 +70,8 @@ class _PollSubmitState extends ConsumerState<PollSubmit> {
|
|||||||
_questions = [...widget.poll.questions]
|
_questions = [...widget.poll.questions]
|
||||||
..sort((a, b) => a.order.compareTo(b.order));
|
..sort((a, b) => a.order.compareTo(b.order));
|
||||||
_answers = Map<String, dynamic>.from(widget.initialAnswers ?? {});
|
_answers = Map<String, dynamic>.from(widget.initialAnswers ?? {});
|
||||||
|
// Set initial collapse state based on the parameter
|
||||||
|
_isCollapsed = !widget.isInitiallyExpanded;
|
||||||
if (!widget.isReadonly) {
|
if (!widget.isReadonly) {
|
||||||
_loadCurrentIntoLocalState();
|
_loadCurrentIntoLocalState();
|
||||||
// If initial answers are provided, set _isModifying to false initially
|
// If initial answers are provided, set _isModifying to false initially
|
||||||
@@ -653,26 +660,160 @@ class _PollSubmitState extends ConsumerState<PollSubmit> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildCollapsedView(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (widget.poll.title != null)
|
||||||
|
Text(
|
||||||
|
widget.poll.title!,
|
||||||
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
if (widget.poll.description != null)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 2),
|
||||||
|
child: Text(
|
||||||
|
widget.poll.description!,
|
||||||
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
|
color: Theme.of(
|
||||||
|
context,
|
||||||
|
).textTheme.bodySmall?.color?.withOpacity(0.7),
|
||||||
|
),
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 2),
|
||||||
|
child: Text(
|
||||||
|
'${_questions.length} question${_questions.length == 1 ? '' : 's'}',
|
||||||
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
|
color: Theme.of(
|
||||||
|
context,
|
||||||
|
).textTheme.bodySmall?.color?.withOpacity(0.7),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(
|
||||||
|
_isCollapsed ? Icons.expand_more : Icons.expand_less,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
_isCollapsed = !_isCollapsed;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
tooltip: _isCollapsed ? 'expandPoll'.tr() : 'collapsePoll'.tr(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (_questions.isEmpty) {
|
if (_questions.isEmpty) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If collapsed, show collapsed view for all states
|
||||||
|
if (_isCollapsed) {
|
||||||
|
return _buildCollapsedView(context);
|
||||||
|
}
|
||||||
|
|
||||||
// If poll is already submitted and not in readonly mode, and not in modification mode, show submitted view
|
// If poll is already submitted and not in readonly mode, and not in modification mode, show submitted view
|
||||||
if (widget.initialAnswers != null && !widget.isReadonly && !_isModifying) {
|
if (widget.initialAnswers != null && !widget.isReadonly && !_isModifying) {
|
||||||
return Column(
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
_buildCollapsedView(context),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
transitionBuilder: (child, anim) {
|
||||||
|
final offset = Tween<Offset>(
|
||||||
|
begin: const Offset(0, -0.1),
|
||||||
|
end: Offset.zero,
|
||||||
|
).animate(CurvedAnimation(parent: anim, curve: Curves.easeOut));
|
||||||
|
final fade = CurvedAnimation(parent: anim, curve: Curves.easeOut);
|
||||||
|
return FadeTransition(
|
||||||
|
opacity: fade,
|
||||||
|
child: SlideTransition(position: offset, child: child),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
key: const ValueKey('submitted_expanded'),
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [_buildSubmittedView(context), _buildNavBar(context)],
|
children: [_buildSubmittedView(context), _buildNavBar(context)],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If poll is in readonly mode, show readonly view
|
// If poll is in readonly mode, show readonly view
|
||||||
if (widget.isReadonly) {
|
if (widget.isReadonly) {
|
||||||
return _buildReadonlyView(context);
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
_buildCollapsedView(context),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
transitionBuilder: (child, anim) {
|
||||||
|
final offset = Tween<Offset>(
|
||||||
|
begin: const Offset(0, -0.1),
|
||||||
|
end: Offset.zero,
|
||||||
|
).animate(CurvedAnimation(parent: anim, curve: Curves.easeOut));
|
||||||
|
final fade = CurvedAnimation(parent: anim, curve: Curves.easeOut);
|
||||||
|
return FadeTransition(
|
||||||
|
opacity: fade,
|
||||||
|
child: SlideTransition(position: offset, child: child),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: _buildReadonlyView(context),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
_buildCollapsedView(context),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
transitionBuilder: (child, anim) {
|
||||||
|
final offset = Tween<Offset>(
|
||||||
|
begin: const Offset(0, -0.1),
|
||||||
|
end: Offset.zero,
|
||||||
|
).animate(CurvedAnimation(parent: anim, curve: Curves.easeOut));
|
||||||
|
final fade = CurvedAnimation(parent: anim, curve: Curves.easeOut);
|
||||||
|
return FadeTransition(
|
||||||
|
opacity: fade,
|
||||||
|
child: SlideTransition(position: offset, child: child),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
key: const ValueKey('normal_expanded'),
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
_buildHeader(context),
|
_buildHeader(context),
|
||||||
@@ -681,12 +822,18 @@ class _PollSubmitState extends ConsumerState<PollSubmit> {
|
|||||||
key: ValueKey(_current.id),
|
key: ValueKey(_current.id),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [_buildBody(context), _buildStats(context, _current)],
|
children: [
|
||||||
|
_buildBody(context),
|
||||||
|
_buildStats(context, _current),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
_buildNavBar(context),
|
_buildNavBar(context),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user