Line data Source code
1 : import 'package:tech_proof/data/repositories/movies_repository_imp.dart';
2 : import 'package:tech_proof/presentation/widgets/tt_loading_logo.dart';
3 : import 'package:tech_proof/presentation/widgets/tt_movie_grid.dart';
4 : import 'package:tech_proof/src/search/presentation/bloc/search_bloc.dart';
5 : import 'package:flutter/material.dart';
6 : import 'package:flutter_bloc/flutter_bloc.dart';
7 : import 'package:flutter_svg/svg.dart';
8 :
9 : class SearchPage extends StatelessWidget {
10 0 : const SearchPage({super.key});
11 :
12 0 : @override
13 : Widget build(BuildContext context) {
14 0 : return BlocProvider(
15 0 : create: (context) =>
16 0 : SearchBloc(movieRepository: context.read<MovieRepositoryImpl>()),
17 0 : child: SearchPageView(),
18 : );
19 : }
20 : }
21 :
22 : class SearchPageView extends StatefulWidget {
23 1 : const SearchPageView({super.key});
24 :
25 2 : @override
26 2 : State<SearchPageView> createState() => _SearchPageViewState();
27 : }
28 :
29 : class _SearchPageViewState extends State<SearchPageView> {
30 : final TextEditingController _searchController = TextEditingController();
31 :
32 2 : @override
33 : void dispose() {
34 4 : _searchController.dispose();
35 2 : super.dispose();
36 : }
37 :
38 2 : @override
39 : Widget build(BuildContext context) {
40 2 : return Scaffold(
41 2 : body: BlocBuilder<SearchBloc, SearchState>(
42 2 : builder: (context, state) {
43 2 : bool showResults = state is SearchLoaded;
44 : double inputHeight = 60.0;
45 : double initialPageHeigh = 250.0;
46 :
47 2 : return SafeArea(
48 2 : child: (state is SearchError)
49 4 : ? Center(child: Text('Error: ${state.message}'))
50 2 : : Stack(
51 2 : children: [
52 2 : AnimatedPositioned(
53 2 : duration: Duration(milliseconds: 300),
54 : curve: Curves.easeOut,
55 : top: showResults
56 : ? 0
57 10 : : MediaQuery.of(context).size.height / 2 -
58 2 : initialPageHeigh / 2,
59 : left: 16,
60 : right: 16,
61 2 : child: Column(
62 2 : children: [
63 2 : SvgPicture.asset(
64 : 'assets/images/tt_ico.svg',
65 : height: 80,
66 : ),
67 2 : SizedBox(height: 16),
68 2 : Container(
69 : height: inputHeight,
70 : alignment: showResults
71 : ? Alignment.topLeft
72 : : Alignment.center,
73 2 : child: TextField(
74 2 : controller: _searchController,
75 2 : decoration: InputDecoration(
76 : hintText: 'Search for movies...',
77 2 : prefixIcon: Icon(Icons.search),
78 2 : border: OutlineInputBorder(
79 2 : borderRadius: BorderRadius.circular(30.0),
80 : ),
81 : ),
82 1 : onChanged: (query) {
83 2 : context.read<SearchBloc>().add(
84 1 : SearchTextChanged(query),
85 : );
86 : },
87 0 : onSubmitted: (query) {
88 0 : context.read<SearchBloc>().add(
89 0 : SearchSubmitted(query),
90 : );
91 : },
92 : ),
93 : ),
94 : ],
95 : ),
96 : ),
97 :
98 : if (showResults)
99 1 : AnimatedPositioned(
100 1 : duration: Duration(milliseconds: 300),
101 : curve: Curves.easeOut,
102 1 : top: inputHeight + 120,
103 : left: 0,
104 : right: 0,
105 : bottom: 0,
106 1 : child: CustomScrollView(
107 1 : slivers: [
108 1 : SliverPadding(
109 : padding: const EdgeInsets.symmetric(horizontal: 16.0),
110 2 : sliver: TtMovieGrid(movieList: state.movies),
111 : ),
112 : ],
113 : ),
114 : ),
115 :
116 2 : if (state is SearchLoading)
117 2 : Positioned(
118 2 : top: inputHeight + 250,
119 : left: 0,
120 : right: 0,
121 : bottom: 0,
122 2 : child: Center(
123 2 : child: TtLoadingLogo(
124 2 : duration: Duration(milliseconds: 1500),
125 : ),
126 : ),
127 : ),
128 : ],
129 : ),
130 : );
131 : },
132 : ),
133 : );
134 : }
135 : }
|