Skip to content

Commit 7208f3d

Browse files
committed
brand_new
1 parent 211658c commit 7208f3d

4 files changed

Lines changed: 182 additions & 51 deletions

File tree

lib/main.dart

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:flutter/material.dart';
2+
import 'package:google_fonts/google_fonts.dart';
23
import 'package:provider/provider.dart';
34

45
import 'providers/task_provider.dart';
@@ -27,15 +28,19 @@ class MyApp extends StatelessWidget {
2728
brightness: Brightness.light,
2829
primarySwatch: Colors.teal,
2930
visualDensity: VisualDensity.adaptivePlatformDensity,
31+
textTheme: GoogleFonts.poppinsTextTheme(
32+
Theme.of(context).textTheme,
33+
),
3034
),
3135
darkTheme: ThemeData(
3236
brightness: Brightness.dark,
3337
primaryColor: Colors.tealAccent,
3438
scaffoldBackgroundColor: const Color(0xFF121212),
3539
cardColor: const Color(0xFF1E1E1E),
36-
textTheme: const TextTheme(
37-
bodyLarge: TextStyle(color: Colors.white),
38-
bodyMedium: TextStyle(color: Colors.white70),
40+
textTheme: GoogleFonts.poppinsTextTheme(
41+
Theme.of(context)
42+
.primaryTextTheme
43+
.apply(bodyColor: Colors.white, displayColor: Colors.white),
3944
),
4045
iconTheme: const IconThemeData(color: Colors.white70),
4146
appBarTheme: const AppBarTheme(

lib/screens/home_page.dart

Lines changed: 150 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:flutter/material.dart';
2+
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
23
import 'package:google_fonts/google_fonts.dart';
34
import 'package:provider/provider.dart';
45
import 'package:table_calendar/table_calendar.dart';
@@ -24,21 +25,43 @@ class _HomePageState extends State<HomePage> {
2425
Priority? _selectedPriority;
2526
bool _isSelectionMode = false;
2627
final Set<String> _selectedTasks = {};
28+
CalendarFormat _calendarFormat = CalendarFormat.week;
29+
bool _isSearching = false;
30+
final _searchController = TextEditingController();
31+
32+
@override
33+
void dispose() {
34+
_searchController.dispose();
35+
super.dispose();
36+
}
37+
38+
void _resetFilters() {
39+
setState(() {
40+
_selectedDay = null;
41+
_searchQuery = '';
42+
_searchController.clear();
43+
_selectedPriority = null;
44+
_focusedDay = DateTime.now();
45+
});
46+
}
2747

2848
@override
2949
Widget build(BuildContext context) {
3050
final taskProvider = Provider.of<TaskProvider>(context);
31-
final tasks = taskProvider.tasks.where((task) => !task.isCompleted).toList();
51+
final tasks =
52+
taskProvider.tasks.where((task) => !task.isCompleted).toList();
3253

3354
return Scaffold(
34-
appBar: _isSelectionMode ? _buildSelectionAppBar() : _buildDefaultAppBar(),
55+
appBar:
56+
_isSelectionMode ? _buildSelectionAppBar() : _buildDefaultAppBar(),
3557
body: Column(
3658
children: [
3759
TableCalendar(
3860
firstDay: DateTime.utc(2000, 1, 1),
3961
lastDay: DateTime.utc(2100, 12, 31),
4062
focusedDay: _focusedDay,
41-
calendarFormat: CalendarFormat.twoWeeks,
63+
calendarFormat: _calendarFormat,
64+
headerStyle: const HeaderStyle(formatButtonVisible: false),
4265
selectedDayPredicate: (day) {
4366
return isSameDay(_selectedDay, day);
4467
},
@@ -55,7 +78,6 @@ class _HomePageState extends State<HomePage> {
5578
},
5679
),
5780
const SizedBox(height: 8.0),
58-
_buildSearchBar(),
5981
Expanded(
6082
child: _buildTaskList(tasks),
6183
),
@@ -67,12 +89,51 @@ class _HomePageState extends State<HomePage> {
6789
onPressed: () => Navigator.of(context).push(
6890
MaterialPageRoute(builder: (_) => const AddTaskPage()),
6991
),
70-
child: const Icon(Icons.add),
92+
child: const FaIcon(FontAwesomeIcons.plus),
7193
),
7294
);
7395
}
7496

7597
AppBar _buildDefaultAppBar() {
98+
if (_isSearching) {
99+
return AppBar(
100+
leading: IconButton(
101+
icon: const FaIcon(FontAwesomeIcons.arrowLeft),
102+
onPressed: () {
103+
setState(() {
104+
_isSearching = false;
105+
_searchQuery = '';
106+
_searchController.clear();
107+
});
108+
},
109+
),
110+
title: TextField(
111+
controller: _searchController,
112+
autofocus: true,
113+
onChanged: (value) {
114+
setState(() {
115+
_searchQuery = value;
116+
});
117+
},
118+
decoration: const InputDecoration(
119+
hintText: 'Search tasks...',
120+
border: InputBorder.none,
121+
),
122+
),
123+
actions: [
124+
IconButton(
125+
icon: const FaIcon(FontAwesomeIcons.times),
126+
onPressed: () {
127+
setState(() {
128+
_searchQuery = '';
129+
_searchController.clear();
130+
});
131+
},
132+
),
133+
],
134+
);
135+
}
136+
76137
return AppBar(
77138
title: Text(
78139
'Task-it',
@@ -83,31 +144,95 @@ class _HomePageState extends State<HomePage> {
83144
),
84145
actions: [
85146
IconButton(
86-
icon: const Icon(Icons.check_circle_outline),
87-
onPressed: () => Navigator.of(context).push(
88-
MaterialPageRoute(builder: (_) => const CompletedTasksPage()),
89-
),
90-
),
91-
PopupMenuButton<Priority>(
92-
onSelected: (priority) {
147+
icon: const FaIcon(FontAwesomeIcons.search),
148+
onPressed: () {
93149
setState(() {
94-
_selectedPriority = priority;
150+
_isSearching = true;
95151
});
96152
},
97-
itemBuilder: (context) => Priority.values
98-
.map((priority) => PopupMenuItem(
99-
value: priority,
100-
child: Text(priority.toString().split('.').last),
101-
))
102-
.toList(),
103-
icon: const Icon(Icons.filter_list),
153+
),
154+
PopupMenuButton<dynamic>(
155+
onSelected: (value) {
156+
if (value == 'clear_priority') {
157+
setState(() {
158+
_selectedPriority = null;
159+
});
160+
} else if (value is Priority) {
161+
setState(() {
162+
_selectedPriority = value;
163+
});
164+
}
165+
},
166+
itemBuilder: (context) => <PopupMenuEntry<dynamic>>[
167+
const PopupMenuItem<dynamic>(
168+
enabled: false,
169+
child: Text('Filter by Priority'),
170+
),
171+
...Priority.values.map((priority) {
172+
return PopupMenuItem<Priority>(
173+
value: priority,
174+
child: Text(' ${priority.toString().split('.').last}'),
175+
);
176+
}).toList(),
177+
if (_selectedPriority != null)
178+
PopupMenuItem<String>(
179+
value: 'clear_priority',
180+
child: const Text(' Clear Filter'),
181+
),
182+
],
183+
icon: const FaIcon(FontAwesomeIcons.filter),
104184
),
105185
IconButton(
106-
icon: const Icon(Icons.settings),
186+
icon: const FaIcon(FontAwesomeIcons.cog),
107187
onPressed: () => Navigator.of(context).push(
108188
MaterialPageRoute(builder: (_) => const SettingsPage()),
109189
),
110190
),
191+
PopupMenuButton<String>(
192+
onSelected: (value) {
193+
if (value == 'toggle_calendar') {
194+
setState(() {
195+
_calendarFormat = _calendarFormat == CalendarFormat.week
196+
? CalendarFormat.month
197+
: CalendarFormat.week;
198+
});
199+
} else if (value == 'reset_filters') {
200+
_resetFilters();
201+
} else if (value == 'completed_tasks') {
202+
Navigator.of(context).push(
203+
MaterialPageRoute(builder: (_) => const CompletedTasksPage()),
204+
);
205+
}
206+
},
207+
itemBuilder: (context) => <PopupMenuEntry<String>>[
208+
PopupMenuItem<String>(
209+
value: 'toggle_calendar',
210+
child: ListTile(
211+
leading: FaIcon(
212+
_calendarFormat == CalendarFormat.week
213+
? FontAwesomeIcons.calendarWeek
214+
: FontAwesomeIcons.calendarDay,
215+
),
216+
title: const Text('Change Calendar View'),
217+
),
218+
),
219+
PopupMenuItem<String>(
220+
value: 'completed_tasks',
221+
child: const ListTile(
222+
leading: FaIcon(FontAwesomeIcons.checkCircle),
223+
title: Text('Completed Tasks'),
224+
),
225+
),
226+
PopupMenuItem<String>(
227+
value: 'reset_filters',
228+
child: const ListTile(
229+
leading: FaIcon(FontAwesomeIcons.arrowsRotate),
230+
title: Text('Reset Filters'),
231+
),
232+
),
233+
],
234+
icon: const FaIcon(FontAwesomeIcons.ellipsisV),
235+
),
111236
],
112237
);
113238
}
@@ -116,7 +241,7 @@ class _HomePageState extends State<HomePage> {
116241
return AppBar(
117242
title: Text('${_selectedTasks.length} selected'),
118243
leading: IconButton(
119-
icon: const Icon(Icons.close),
244+
icon: const FaIcon(FontAwesomeIcons.times),
120245
onPressed: () {
121246
setState(() {
122247
_isSelectionMode = false;
@@ -126,9 +251,10 @@ class _HomePageState extends State<HomePage> {
126251
),
127252
actions: [
128253
IconButton(
129-
icon: const Icon(Icons.delete),
254+
icon: const FaIcon(FontAwesomeIcons.trash),
130255
onPressed: () {
131-
final taskProvider = Provider.of<TaskProvider>(context, listen: false);
256+
final taskProvider =
257+
Provider.of<TaskProvider>(context, listen: false);
132258
for (final taskId in _selectedTasks) {
133259
taskProvider.deleteTask(taskId);
134260
}
@@ -142,26 +268,6 @@ class _HomePageState extends State<HomePage> {
142268
);
143269
}
144270

145-
Widget _buildSearchBar() {
146-
return Padding(
147-
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
148-
child: TextField(
149-
onChanged: (value) {
150-
setState(() {
151-
_searchQuery = value;
152-
});
153-
},
154-
decoration: InputDecoration(
155-
hintText: 'Search...',
156-
prefixIcon: const Icon(Icons.search),
157-
border: OutlineInputBorder(
158-
borderRadius: BorderRadius.circular(12.0),
159-
),
160-
),
161-
),
162-
);
163-
}
164-
165271
Widget _buildTaskList(List<Task> tasks) {
166272
List<Task> filteredTasks = tasks;
167273

lib/screens/view_task_page.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ class ViewTaskPage extends StatelessWidget {
8787
onPressed: () {
8888
Provider.of<TaskProvider>(context, listen: false)
8989
.deleteTask(task.id);
90-
Navigator.of(context).popUntil((route) => route.isFirst);
90+
Navigator.of(context)
91+
.popUntil((route) => route.isFirst);
9192
},
9293
child: const Text('Delete'),
9394
),
@@ -178,7 +179,8 @@ class ViewTaskPage extends StatelessWidget {
178179
style: TextStyle(
179180
fontSize: 20,
180181
fontWeight: FontWeight.bold,
181-
color: valueColor ?? Theme.of(context).textTheme.bodyLarge?.color,
182+
color: valueColor ??
183+
Theme.of(context).textTheme.bodyLarge?.color,
182184
),
183185
),
184186
],

lib/widgets/task_list_item.dart

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import 'dart:async';
22

33
import 'package:flutter/material.dart';
44
import 'package:provider/provider.dart';
5-
import 'package:timeago/timeago.dart' as timeago;
65

76
import '../models/task.dart';
87
import '../providers/task_provider.dart';
@@ -45,6 +44,25 @@ class _TaskListItemState extends State<TaskListItem> {
4544
super.dispose();
4645
}
4746

47+
String _formatDueDate(DateTime dueDate) {
48+
final now = DateTime.now();
49+
final difference = dueDate.difference(now);
50+
51+
if (difference.isNegative) {
52+
return 'Overdue';
53+
}
54+
55+
if (difference.inDays > 0) {
56+
return '${difference.inDays}d left';
57+
} else if (difference.inHours > 0) {
58+
return '${difference.inHours}h left';
59+
} else if (difference.inMinutes > 0) {
60+
return '${difference.inMinutes}m left';
61+
} else {
62+
return 'Due soon';
63+
}
64+
}
65+
4866
@override
4967
Widget build(BuildContext context) {
5068
final taskProvider = Provider.of<TaskProvider>(context, listen: false);
@@ -159,7 +177,7 @@ class _TaskListItemState extends State<TaskListItem> {
159177
),
160178
const SizedBox(height: 4),
161179
Text(
162-
timeago.format(widget.task.dueDate),
180+
_formatDueDate(widget.task.dueDate),
163181
style: const TextStyle(
164182
color: Colors.grey, fontSize: 14),
165183
),

0 commit comments

Comments
 (0)