Skip to content
This repository was archived by the owner on Jul 12, 2024. It is now read-only.

Commit 16f3184

Browse files
authored
Merge pull request #27 from langx/feature-community-filters
Feature community filters
2 parents 4362d7d + 3cfc037 commit 16f3184

File tree

5 files changed

+350
-7
lines changed

5 files changed

+350
-7
lines changed

lib/assets/svg/country_svg.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class CountrySvg extends StatelessWidget {
2828

2929
@override
3030
Widget build(BuildContext context) {
31-
final Color defaultColor = color ?? Colors.black;
31+
final Color defaultColor = color ?? Colors.yellow[700]!;
3232
String infoSvg = generateCountrySvg(fill, strokeWidth, defaultColor);
3333
return SvgPicture.string(
3434
infoSvg,

lib/assets/svg/sex_svg.dart

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_svg/flutter_svg.dart';
3+
4+
class SexSvg extends StatelessWidget {
5+
final String fill;
6+
final int strokeWidth;
7+
final Color? color;
8+
final double widht;
9+
final double height;
10+
11+
const SexSvg(
12+
{super.key,
13+
this.color,
14+
this.fill = "none",
15+
this.strokeWidth = 30,
16+
this.widht = 17,
17+
this.height = 17});
18+
19+
String generateSexSvg(String fillColor, int strokeWidth, Color color) {
20+
final colorHex = '#${color.value.toRadixString(16).substring(2)}';
21+
return '''
22+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
23+
<circle cx="216" cy="200" r="136" stroke="$colorHex" stroke-width="$strokeWidth" fill="$fillColor"></circle>
24+
<path d="M216 352v128M272 416H160M432 112V32h-80M335.28 128.72L432 32" stroke="$colorHex" stroke-width="$strokeWidth" fill="$fillColor"></path>
25+
</svg>
26+
''';
27+
}
28+
29+
@override
30+
Widget build(BuildContext context) {
31+
final Color defaultColor = color ?? Colors.yellow[700]!;
32+
String infoSvg = generateSexSvg(fill, strokeWidth, defaultColor);
33+
return SvgPicture.string(
34+
infoSvg,
35+
width: widht,
36+
height: height,
37+
);
38+
}
39+
}

lib/assets/svg/switch_svg.dart

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_svg/flutter_svg.dart';
3+
4+
class SwitchSvg extends StatelessWidget {
5+
final String fill;
6+
final int strokeWidth;
7+
final Color? color;
8+
final double widht;
9+
final double height;
10+
11+
const SwitchSvg(
12+
{super.key,
13+
this.color,
14+
this.fill = "none",
15+
this.strokeWidth = 30,
16+
this.widht = 17,
17+
this.height = 17});
18+
19+
String generateSwitchSvg(String fillColor, int strokeWidth, Color color) {
20+
final colorHex = '#${color.value.toRadixString(16).substring(2)}';
21+
return '''
22+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
23+
<circle cx="368" cy="256" r="128" stroke="$colorHex" stroke-width="$strokeWidth" fill="$fillColor"></circle>
24+
<rect x="16" y="128" width="480" height="256" rx="128" ry="128" stroke="$colorHex" stroke-width="$strokeWidth" fill="$fillColor"></rect>
25+
</svg>
26+
''';
27+
}
28+
29+
@override
30+
Widget build(BuildContext context) {
31+
final Color defaultColor = color ?? Colors.yellow[700]!;
32+
String infoSvg = generateSwitchSvg(fill, strokeWidth, defaultColor);
33+
return SvgPicture.string(
34+
infoSvg,
35+
width: widht,
36+
height: height,
37+
);
38+
}
39+
}

lib/pages/home/community.dart

+21-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
55
import 'package:langx_flutter/components/community/usercard.dart';
66
import 'package:langx_flutter/providers/user_provider.dart';
77

8+
// Pages Import
9+
import 'package:langx_flutter/pages/home/filters.dart';
10+
811
class Community extends ConsumerStatefulWidget {
912
const Community({super.key});
1013

@@ -65,23 +68,35 @@ class _CommunityState extends ConsumerState<Community> {
6568
backgroundColor: const Color.fromARGB(31, 163, 163, 163),
6669
body: CustomScrollView(
6770
slivers: [
68-
const SliverAppBar(
71+
SliverAppBar(
6972
title: Row(
7073
mainAxisAlignment: MainAxisAlignment.spaceBetween,
7174
children: [
72-
Text("Community"),
75+
const Text("Community"),
7376
Row(
7477
children: [
75-
Icon(Icons.search, size: 30),
76-
SizedBox(width: 10.0),
77-
Icon(Icons.filter_list, size: 30),
78+
IconButton(
79+
icon: const Icon(Icons.search, size: 30),
80+
onPressed: () {},
81+
),
82+
const SizedBox(width: 10.0),
83+
IconButton(
84+
icon: const Icon(Icons.filter_list, size: 30),
85+
onPressed: () {
86+
Navigator.push(
87+
context,
88+
MaterialPageRoute(
89+
builder: (context) => const FiltersPage()),
90+
);
91+
},
92+
),
7893
],
7994
),
8095
],
8196
),
8297
centerTitle: false,
8398
pinned: true,
84-
backgroundColor: Color(0xFFFBC02D),
99+
backgroundColor: const Color(0xFFFBC02D),
85100
foregroundColor: Colors.black,
86101
),
87102
SliverToBoxAdapter(

lib/pages/home/filters.dart

+250
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
import 'package:flutter/material.dart';
2+
3+
import 'package:langx_flutter/assets/svg/battery_svg.dart';
4+
import 'package:langx_flutter/assets/svg/word_svg.dart';
5+
import 'package:langx_flutter/assets/svg/country_svg.dart';
6+
import 'package:langx_flutter/assets/svg/sex_svg.dart';
7+
import 'package:langx_flutter/assets/svg/switch_svg.dart';
8+
9+
class FiltersPage extends StatefulWidget {
10+
const FiltersPage({super.key});
11+
12+
@override
13+
FiltersPageState createState() => FiltersPageState();
14+
}
15+
16+
typedef BoolCallback = void Function(bool? value);
17+
18+
class FiltersPageState extends State<FiltersPage> {
19+
bool matchMyGender = false;
20+
bool _motherEnglish = false;
21+
bool _motherChinese = false;
22+
bool _studyEnglish = false;
23+
bool _studyChinese = false;
24+
25+
RangeValues rangeValues = const RangeValues(18, 60);
26+
String rangeLable = 'No Filter';
27+
28+
@override
29+
Widget build(BuildContext context) {
30+
return Scaffold(
31+
backgroundColor: Colors.white,
32+
appBar: AppBar(
33+
backgroundColor: Colors.yellow[700],
34+
leading: IconButton(
35+
icon: const Icon(Icons.arrow_back),
36+
onPressed: () {
37+
Navigator.pop(context);
38+
},
39+
),
40+
title: const Text('Filters'),
41+
actions: [
42+
IconButton(
43+
icon: const Icon(Icons.refresh),
44+
onPressed: () {},
45+
),
46+
IconButton(
47+
icon: const Icon(Icons.check),
48+
onPressed: () {},
49+
),
50+
],
51+
),
52+
body: ListView(
53+
padding: const EdgeInsets.all(8.0),
54+
children: [
55+
_buildFilterSection(
56+
title: 'Mother Language',
57+
options: [
58+
_buildOptionRow(
59+
'English',
60+
const BatterySvg(widht: 25, height: 25),
61+
_motherEnglish, (bool? value) {
62+
setState(() {
63+
_motherEnglish = value ?? false;
64+
});
65+
}),
66+
_buildOptionRow(
67+
'Chinese (Simplified)',
68+
const WordSvg(widht: 25, height: 25),
69+
_motherChinese, (bool? value) {
70+
setState(() {
71+
_motherChinese = value ?? false;
72+
});
73+
}),
74+
],
75+
),
76+
_buildFilterSection(
77+
title: 'Study Language',
78+
options: [
79+
_buildOptionRow(
80+
'English',
81+
const BatterySvg(widht: 25, height: 25),
82+
_studyEnglish, (bool? value) {
83+
setState(() {
84+
_studyEnglish = value ?? false;
85+
});
86+
}),
87+
_buildOptionRow(
88+
'Chinese (Simplified)',
89+
const WordSvg(widht: 25, height: 25),
90+
_studyChinese, (bool? value) {
91+
setState(() {
92+
_studyChinese = value ?? false;
93+
});
94+
}),
95+
],
96+
),
97+
_buildFilterSection(
98+
title: 'Country',
99+
options: [
100+
_buildOptionRow2(
101+
'No Filter', const CountrySvg(widht: 25, height: 25)),
102+
],
103+
),
104+
_buildFilterSection(
105+
title: 'Gender',
106+
options: [
107+
_buildOptionRow2(
108+
'No Filter', const SexSvg(widht: 25, height: 25)),
109+
_buildOptionRow2(
110+
'Match My Gender', const SwitchSvg(widht: 25, height: 25)),
111+
],
112+
),
113+
_buildFilterSection(
114+
title: 'Age',
115+
options: [
116+
Container(
117+
decoration: const BoxDecoration(
118+
border: Border(
119+
bottom: BorderSide(
120+
color: Colors.grey,
121+
width: 1.0,
122+
),
123+
),
124+
),
125+
child: ListTile(
126+
leading:
127+
Icon(Icons.calendar_today, color: Colors.yellow[700]),
128+
title: Text(rangeLable),
129+
),
130+
),
131+
Padding(
132+
padding: const EdgeInsets.symmetric(horizontal: 16.0),
133+
child: RangeSlider(
134+
activeColor: Colors.yellow[700],
135+
values: rangeValues,
136+
min: 0,
137+
max: 100,
138+
divisions: 100,
139+
labels: RangeLabels(
140+
rangeValues.start.round().toString(),
141+
rangeValues.end.round().toString(),
142+
),
143+
onChanged: (RangeValues values) {
144+
setState(() {
145+
rangeValues = values;
146+
147+
rangeLable =
148+
"between ${rangeValues.start.round().toString()} and ${rangeValues.end.round().toString()} ";
149+
});
150+
},
151+
),
152+
),
153+
],
154+
),
155+
Padding(
156+
padding: const EdgeInsets.all(16.0),
157+
child: ElevatedButton(
158+
style: ElevatedButton.styleFrom(
159+
backgroundColor: Colors.yellow[700],
160+
foregroundColor: Colors.white,
161+
padding: const EdgeInsets.symmetric(vertical: 16.0),
162+
),
163+
onPressed: () {},
164+
child: const Text(
165+
'APPLY',
166+
style: TextStyle(fontSize: 16),
167+
),
168+
),
169+
),
170+
],
171+
),
172+
);
173+
}
174+
175+
Widget _buildFilterSection({
176+
required String title,
177+
required List<Widget> options,
178+
bool hasArrow = false,
179+
}) {
180+
return Card(
181+
elevation: 8.0,
182+
color: Colors.white,
183+
shape: RoundedRectangleBorder(
184+
borderRadius: BorderRadius.circular(16.0),
185+
),
186+
margin: const EdgeInsets.symmetric(vertical: 4.0),
187+
child: Padding(
188+
padding: const EdgeInsets.all(8.0),
189+
child: Column(
190+
crossAxisAlignment: CrossAxisAlignment.start,
191+
children: [
192+
ListTile(
193+
title: Text(title),
194+
trailing: hasArrow ? const Icon(Icons.arrow_forward_ios) : null,
195+
),
196+
Column(children: options),
197+
],
198+
),
199+
),
200+
);
201+
}
202+
203+
Widget _buildOptionRow(String text, StatelessWidget icon, bool selection,
204+
BoolCallback onChange) {
205+
return Container(
206+
decoration: const BoxDecoration(
207+
border: Border(
208+
bottom: BorderSide(
209+
color: Colors.grey,
210+
width: 1.0,
211+
),
212+
),
213+
),
214+
child: ListTile(
215+
leading: icon,
216+
title: Text(text),
217+
trailing: Checkbox(
218+
activeColor: Colors.yellow[700],
219+
checkColor: Colors.black,
220+
value: selection,
221+
onChanged: onChange),
222+
),
223+
);
224+
}
225+
226+
Widget _buildOptionRow2(String text, StatelessWidget icon) {
227+
return Container(
228+
decoration: const BoxDecoration(
229+
border: Border(
230+
bottom: BorderSide(
231+
color: Colors.grey,
232+
width: 1.0,
233+
),
234+
),
235+
),
236+
child: ListTile(
237+
leading: icon,
238+
title: Text(text),
239+
trailing: IconButton(
240+
iconSize: 30,
241+
icon: const Icon(Icons.chevron_right),
242+
onPressed: () {
243+
debugPrint("Print");
244+
},
245+
color: Colors.grey,
246+
),
247+
),
248+
);
249+
}
250+
}

0 commit comments

Comments
 (0)