Skip to content

Commit aac70cb

Browse files
committed
add search bar on home screen
1 parent 1829bf5 commit aac70cb

File tree

6 files changed

+316
-67
lines changed

6 files changed

+316
-67
lines changed

android/app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ android {
3030
applicationId = "com.example.the_wallpaper_company"
3131
// You can update the following values to match your application needs.
3232
// For more information, see: https://flutter.dev/to/review-gradle-config.
33-
minSdk = 23
33+
minSdk = flutter.minSdkVersion
3434
targetSdk = flutter.targetSdkVersion
3535
versionCode = flutter.versionCode
3636
versionName = flutter.versionName
@@ -60,4 +60,4 @@ dependencies {
6060
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
6161

6262
// Other dependencies for your project...
63-
}
63+
}

lib/features/home/presentation/screen/home_screen.dart

Lines changed: 64 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import 'package:the_wallpaper_company/features/home/presentation/widgets/wallpap
1212
import 'package:the_wallpaper_company/features/home/provider/wallpaper_provider.dart';
1313
import 'package:the_wallpaper_company/firebase_message.dart';
1414
import '../widgets/category_carousel.dart';
15+
import '../widgets/search_bar_widget.dart';
16+
import '../widgets/no_results_widget.dart';
1517
import 'package:the_wallpaper_company/core/constants.dart';
1618
import 'package:the_wallpaper_company/features/home/presentation/widgets/wallpaper_tile.dart';
1719
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
@@ -121,60 +123,76 @@ class _HomeScreenState extends State<HomeScreen> {
121123
sigmaX: 12,
122124
sigmaY: 12,
123125
),
124-
child: CategoryCarousel(
125-
categories: AppConstants.categories,
126-
selectedCategory:
127-
provider.selectedCategory,
128-
onCategorySelected:
129-
provider.selectCategory,
126+
child: Column(
127+
children: [
128+
const SearchBarWidget(),
129+
CategoryCarousel(
130+
categories:
131+
AppConstants.categories,
132+
selectedCategory:
133+
provider.selectedCategory,
134+
onCategorySelected:
135+
provider.selectCategory,
136+
),
137+
],
130138
),
131139
),
132140
),
133141
),
134142
// expandedHeight: 72,
135-
toolbarHeight: 150,
143+
toolbarHeight: 220,
136144
),
137-
SliverPadding(
138-
padding: const EdgeInsets.symmetric(
139-
horizontal: 8,
140-
vertical: 8,
141-
),
142-
sliver: SliverMasonryGrid.count(
143-
crossAxisCount: 2,
144-
mainAxisSpacing: 8,
145-
crossAxisSpacing: 8,
146-
childCount:
147-
visibleWallpapers.length +
148-
(provider.isPaginating ? 1 : 0),
149-
itemBuilder: (context, index) {
150-
if (provider.isPaginating &&
151-
index == visibleWallpapers.length) {
152-
return const WallpaperShimmer();
153-
}
154-
final wallpaper =
155-
visibleWallpapers[index];
156-
return InkWell(
157-
onTap: () {
158-
Navigator.of(context).push(
159-
MaterialPageRoute(
160-
builder: (context) =>
161-
WallpaperScreen(
162-
wallpapers:
163-
visibleWallpapers,
164-
initialIndex: index,
145+
visibleWallpapers.isEmpty &&
146+
provider.searchQuery.isNotEmpty
147+
? SliverFillRemaining(
148+
child: NoResultsWidget(
149+
searchQuery: provider.searchQuery,
150+
onClearSearch: provider.clearSearch,
151+
),
152+
)
153+
: SliverPadding(
154+
padding: const EdgeInsets.symmetric(
155+
horizontal: 8,
156+
vertical: 8,
157+
),
158+
sliver: SliverMasonryGrid.count(
159+
crossAxisCount: 2,
160+
mainAxisSpacing: 8,
161+
crossAxisSpacing: 8,
162+
childCount:
163+
visibleWallpapers.length +
164+
(provider.isPaginating ? 1 : 0),
165+
itemBuilder: (context, index) {
166+
if (provider.isPaginating &&
167+
index ==
168+
visibleWallpapers
169+
.length) {
170+
return const WallpaperShimmer();
171+
}
172+
final wallpaper =
173+
visibleWallpapers[index];
174+
return InkWell(
175+
onTap: () {
176+
Navigator.of(context).push(
177+
MaterialPageRoute(
178+
builder: (context) =>
179+
WallpaperScreen(
180+
wallpapers:
181+
visibleWallpapers,
182+
initialIndex: index,
183+
),
165184
),
166-
),
167-
);
168-
},
169-
child: WallpaperTile(
170-
imageUrl: wallpaper.imageUrl,
171-
title: wallpaper.title,
172-
id: wallpaper.id,
185+
);
186+
},
187+
child: WallpaperTile(
188+
imageUrl: wallpaper.imageUrl,
189+
title: wallpaper.title,
190+
id: wallpaper.id,
191+
),
192+
);
193+
},
173194
),
174-
);
175-
},
176-
),
177-
),
195+
),
178196
],
179197
),
180198
),
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import 'package:flutter/material.dart';
2+
3+
class NoResultsWidget extends StatelessWidget {
4+
final String searchQuery;
5+
final VoidCallback onClearSearch;
6+
7+
const NoResultsWidget({
8+
super.key,
9+
required this.searchQuery,
10+
required this.onClearSearch,
11+
});
12+
13+
@override
14+
Widget build(BuildContext context) {
15+
return Center(
16+
child: Padding(
17+
padding: const EdgeInsets.all(32.0),
18+
child: Column(
19+
mainAxisAlignment: MainAxisAlignment.center,
20+
children: [
21+
Icon(
22+
Icons.search_off,
23+
size: 64,
24+
color: Theme.of(context).brightness == Brightness.dark
25+
? Colors.grey[600]
26+
: Colors.grey[400],
27+
),
28+
const SizedBox(height: 16),
29+
Text(
30+
'No wallpapers found',
31+
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
32+
color: Theme.of(context).brightness == Brightness.dark
33+
? Colors.grey[400]
34+
: Colors.grey[600],
35+
fontWeight: FontWeight.w600,
36+
),
37+
),
38+
const SizedBox(height: 8),
39+
Text(
40+
'No results for "${searchQuery.trim()}"',
41+
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
42+
color: Theme.of(context).brightness == Brightness.dark
43+
? Colors.grey[500]
44+
: Colors.grey[500],
45+
),
46+
textAlign: TextAlign.center,
47+
),
48+
const SizedBox(height: 24),
49+
ElevatedButton.icon(
50+
onPressed: onClearSearch,
51+
icon: const Icon(Icons.clear),
52+
label: const Text('Clear Search'),
53+
style: ElevatedButton.styleFrom(
54+
padding: const EdgeInsets.symmetric(
55+
horizontal: 24,
56+
vertical: 12,
57+
),
58+
shape: RoundedRectangleBorder(
59+
borderRadius: BorderRadius.circular(25),
60+
),
61+
),
62+
),
63+
],
64+
),
65+
),
66+
);
67+
}
68+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:provider/provider.dart';
3+
import '../../provider/wallpaper_provider.dart';
4+
5+
class SearchBarWidget extends StatefulWidget {
6+
const SearchBarWidget({super.key});
7+
8+
@override
9+
State<SearchBarWidget> createState() => _SearchBarWidgetState();
10+
}
11+
12+
class _SearchBarWidgetState extends State<SearchBarWidget> {
13+
final TextEditingController _searchController = TextEditingController();
14+
final FocusNode _focusNode = FocusNode();
15+
16+
@override
17+
void initState() {
18+
super.initState();
19+
final provider = Provider.of<WallpaperProvider>(context, listen: false);
20+
_searchController.text = provider.searchQuery;
21+
}
22+
23+
@override
24+
void dispose() {
25+
_searchController.dispose();
26+
_focusNode.dispose();
27+
super.dispose();
28+
}
29+
30+
@override
31+
Widget build(BuildContext context) {
32+
return Consumer<WallpaperProvider>(
33+
builder: (context, provider, child) {
34+
return Container(
35+
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
36+
decoration: BoxDecoration(
37+
color: Theme.of(context).brightness == Brightness.dark
38+
? Colors.grey[800]?.withValues(alpha: 0.8)
39+
: Colors.white.withValues(alpha: 0.8),
40+
borderRadius: BorderRadius.circular(25),
41+
boxShadow: [
42+
BoxShadow(
43+
color: Colors.black.withValues(alpha: 0.1),
44+
blurRadius: 10,
45+
offset: const Offset(0, 2),
46+
),
47+
],
48+
),
49+
child: TextField(
50+
controller: _searchController,
51+
focusNode: _focusNode,
52+
onChanged: (value) {
53+
provider.updateSearchQuery(value);
54+
},
55+
decoration: InputDecoration(
56+
hintText: 'Search wallpapers by title or category...',
57+
hintStyle: TextStyle(
58+
color: Theme.of(context).brightness == Brightness.dark
59+
? Colors.grey[400]
60+
: Colors.grey[600],
61+
fontSize: 16,
62+
),
63+
prefixIcon: Icon(
64+
provider.searchQuery.isNotEmpty ? Icons.search : Icons.search,
65+
color: provider.searchQuery.isNotEmpty
66+
? Colors.pinkAccent
67+
: (Theme.of(context).brightness == Brightness.dark
68+
? Colors.grey[400]
69+
: Colors.grey[600]),
70+
size: 24,
71+
),
72+
suffixIcon: provider.searchQuery.isNotEmpty
73+
? IconButton(
74+
icon: Icon(
75+
Icons.clear,
76+
color: Theme.of(context).brightness == Brightness.dark
77+
? Colors.grey[400]
78+
: Colors.grey[600],
79+
size: 20,
80+
),
81+
onPressed: () {
82+
_searchController.clear();
83+
provider.clearSearch();
84+
_focusNode.unfocus();
85+
},
86+
)
87+
: null,
88+
border: InputBorder.none,
89+
contentPadding: const EdgeInsets.symmetric(
90+
horizontal: 20,
91+
vertical: 16,
92+
),
93+
),
94+
style: TextStyle(
95+
color: Theme.of(context).brightness == Brightness.dark
96+
? Colors.white
97+
: Colors.black87,
98+
fontSize: 16,
99+
),
100+
),
101+
);
102+
},
103+
);
104+
}
105+
}

0 commit comments

Comments
 (0)