Skip to content
This repository has been archived by the owner on Jan 9, 2024. It is now read-only.

Commit

Permalink
fix: summary jump (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
RuiMiguel authored Dec 1, 2023
1 parent 90c8ce5 commit 485cbfa
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 77 deletions.
168 changes: 107 additions & 61 deletions lib/home/widgets/results_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class SearchBoxViewState extends State<SearchBoxView>
Widget build(BuildContext context) {
return Container(
constraints: const BoxConstraints(
maxWidth: 595,
maxWidth: 659,
),
child: SlideTransition(
position: _offset,
Expand Down Expand Up @@ -253,7 +253,7 @@ class BlueContainerState extends State<BlueContainer>

void _initSizeIn() {
sizeIn = Tween<Size>(
begin: const Size(600, 700),
begin: const Size(659, 732),
end: Size(
widget.constraints.maxWidth,
widget.constraints.maxHeight,
Expand Down Expand Up @@ -322,12 +322,12 @@ class _AiResponseState extends State<_AiResponse>

enterTransitionController = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
duration: const Duration(seconds: 2),
);

exitTransitionController = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
duration: const Duration(milliseconds: 800),
);
}

Expand Down Expand Up @@ -429,76 +429,122 @@ class _AiResponseState extends State<_AiResponse>
}
}

class SummaryView extends StatelessWidget {
class SummaryView extends StatefulWidget {
const SummaryView({
super.key,
});

@override
State<SummaryView> createState() => _SummaryViewState();
}

class _SummaryViewState extends State<SummaryView>
with TickerProviderStateMixin, TransitionScreenMixin {
late Animation<double> _width;

@override
List<Status> get forwardExitStatuses => [Status.resultsToSourceAnswers];

@override
List<Status> get backEnterStatuses => [Status.sourceAnswersBackToResults];

@override
void initializeTransitionController() {
super.initializeTransitionController();

enterTransitionController = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
);

exitTransitionController = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
);
}

@override
void initState() {
super.initState();

_width = Tween<double>(begin: 563, end: 659).animate(
CurvedAnimation(
parent: exitTransitionController,
curve: Curves.decelerate,
),
);
}

@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
final parsed = context.select((HomeBloc bloc) => bloc.state.parsedSummary);

return SizedBox(
width: 540,
child: RichText(
text: TextSpan(
children: [
for (final element in parsed.elements)
if (element.isLink)
WidgetSpan(
child: InkWell(
onTap: () {
final isOnSeeSourceAnswers =
context.read<HomeBloc>().state.status ==
Status.seeSourceAnswers;
if (isOnSeeSourceAnswers) {
context.read<HomeBloc>().add(
NavigateSourceAnswers(
element.text,
),
);
} else {
context.read<HomeBloc>().add(
SeeSourceAnswersRequested(
element.text,
),
);
}
},
child: Container(
margin: const EdgeInsets.symmetric(
horizontal: 2,
),
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 12,
),
decoration: const BoxDecoration(
color: VertexColors.white,
borderRadius: BorderRadius.all(
Radius.circular(100),
return AnimatedBuilder(
animation: _width,
builder: (context, child) {
return SizedBox(
width: _width.value,
child: RichText(
text: TextSpan(
children: [
for (final element in parsed.elements)
if (element.isLink)
WidgetSpan(
child: InkWell(
onTap: () {
final isOnSeeSourceAnswers =
context.read<HomeBloc>().state.status ==
Status.seeSourceAnswers;
if (isOnSeeSourceAnswers) {
context.read<HomeBloc>().add(
NavigateSourceAnswers(
element.text,
),
);
} else {
context.read<HomeBloc>().add(
SeeSourceAnswersRequested(
element.text,
),
);
}
},
child: Container(
margin: const EdgeInsets.symmetric(
horizontal: 2,
),
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 12,
),
decoration: const BoxDecoration(
color: VertexColors.white,
borderRadius: BorderRadius.all(
Radius.circular(100),
),
),
child: Text(
element.text,
style: textTheme.labelLarge?.copyWith(
color: VertexColors.googleBlue,
),
),
),
),
child: Text(
element.text,
style: textTheme.labelLarge?.copyWith(
color: VertexColors.googleBlue,
),
)
else
TextSpan(
text: element.text,
style: textTheme.headlineLarge?.copyWith(
color: VertexColors.white,
),
),
),
)
else
TextSpan(
text: element.text,
style: textTheme.headlineLarge?.copyWith(
color: VertexColors.white,
),
),
],
),
),
],
),
),
);
},
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class _QuestionTextFieldState extends State<QuestionInputTextField> {
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
return Container(
constraints: const BoxConstraints(maxWidth: 600),
constraints: const BoxConstraints(maxWidth: 659),
child: TextField(
controller: _controller,
style: textTheme.bodyMedium?.copyWith(
Expand Down
38 changes: 23 additions & 15 deletions test/home/widgets/results_view_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:api_client/api_client.dart';
import 'package:app_ui/app_ui.dart';
import 'package:bloc_test/bloc_test.dart';
import 'package:dash_ai_search/home/home.dart';
import 'package:dash_ai_search/l10n/l10n.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_test/flutter_test.dart';
Expand Down Expand Up @@ -150,15 +151,6 @@ void main() {
expect(sizeIn, isNot(equals(originalSizeIn)));
});

testWidgets(
'calls Results on enter',
(WidgetTester tester) async {
await tester.pumpApp(bootstrap());
await tester.pumpAndSettle();
verify(() => homeBloc.add(Results())).called(1);
},
);

testWidgets(
'calls SeeResultsSourceAnswers on exit',
(WidgetTester tester) async {
Expand Down Expand Up @@ -201,8 +193,18 @@ void main() {
(tester) async {
await tester.pumpApp(bootstrap());

await tester.pumpAndSettle();
await tester.tap(find.byType(SeeSourceAnswersButton));
final l10n = tester.element(find.byType(ResultsView)).l10n;

await tester.pump();
tester
.widget<TertiaryCTA>(
find.ancestor(
of: find.text(l10n.seeSourceAnswers),
matching: find.byType(TertiaryCTA),
),
)
.onPressed
?.call();

verify(() => homeBloc.add(const SeeSourceAnswersRequested(null)))
.called(1);
Expand All @@ -211,8 +213,11 @@ void main() {
testWidgets('adds AnswerFeedback.good on thumbs up', (tester) async {
await tester.pumpApp(bootstrap());

await tester.pumpAndSettle();
await tester.tap(find.byType(CircleAvatar).first);
await tester.pump();
tester
.widget<FeedbackButtons>(find.byType(FeedbackButtons))
.onLike
?.call();

verify(
() => homeBloc.add(
Expand All @@ -224,8 +229,11 @@ void main() {
testWidgets('adds AnswerFeedback.bad on thumbs down', (tester) async {
await tester.pumpApp(bootstrap());

await tester.pumpAndSettle();
await tester.tap(find.byType(CircleAvatar).last);
await tester.pump();
tester
.widget<FeedbackButtons>(find.byType(FeedbackButtons))
.onDislike
?.call();

verify(
() => homeBloc.add(
Expand Down

0 comments on commit 485cbfa

Please sign in to comment.