Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions task_manager_app/lib/Todo.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class Todo {
final int id;
final int userId;
final String title;
final bool completed;

Todo({required this.id, required this.userId, required this.title, required this.completed});

factory Todo.fromJson(Map<String, dynamic> json) {
return Todo(
id: json['id'],
userId: json['userId'],
title: json['title'],
completed: json['completed'],
);
}
}
43 changes: 43 additions & 0 deletions task_manager_app/lib/TodoProvider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:task_manager_app/Todo.dart';
import 'dart:convert';


class TodoProvider with ChangeNotifier {
List<Todo> _items = [];
bool _isLoading = false;
String? _errorMessage;

List<Todo> get items => _items;
bool get isLoading => _isLoading;
String? get errorMessage => _errorMessage;

Future<void> fetchTodos() async {
_isLoading = true;
_errorMessage = null;
notifyListeners();

final stopwatch = Stopwatch()..start();

try {
final response = await http.get(
Uri.parse('https://jsonplaceholder.typicode.com/todos?_limit=20'),
);

if (response.statusCode == 200) {
List<dynamic> data = json.decode(response.body);
_items = data.map((item) => Todo.fromJson(item)).toList();
} else {
_errorMessage = "Server Error: ${response.statusCode}";
}
} catch (e) {
_errorMessage = "Failed to load data. Please check your connection.";
} finally {
_isLoading = false;
stopwatch.stop();
print("Fetch took: ${stopwatch.elapsedMilliseconds}ms"); // Performance log
notifyListeners();
}
}
}
79 changes: 67 additions & 12 deletions task_manager_app/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,24 +1,79 @@
import 'package:flutter/material.dart';
import 'student_registration_screen.dart';
import 'home_page.dart';
import 'package:provider/provider.dart';
import 'package:task_manager_app/TodoProvider.dart';


void main() {
runApp(const TaskManagerApp());
runApp(
ChangeNotifierProvider(
create: (context) => TodoProvider()..fetchTodos(),
child: const MyApp(),
),
);
}

class TaskManagerApp extends StatelessWidget {
const TaskManagerApp({super.key});
class MyApp extends StatelessWidget {
const MyApp({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Task Manager',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const HomePage(),
// home: const StudentRegistrationScreen(),
home: const TodoListScreen(),
);
}
}

class TodoListScreen extends StatelessWidget {
const TodoListScreen({super.key});

@override
Widget build(BuildContext context) {
final provider = Provider.of<TodoProvider>(context);

return Scaffold(
appBar: AppBar(title: const Text('Group 1 - Todos')),
body: RefreshIndicator(
onRefresh: () => provider.fetchTodos(),
child: _buildBody(provider),
),
floatingActionButton: FloatingActionButton(
onPressed: () => provider.fetchTodos(),
child: const Icon(Icons.refresh),
),
);
}

Widget _buildBody(TodoProvider provider) {
if (provider.isLoading) {
return const Center(child: CircularProgressIndicator());
}

if (provider.errorMessage != null) {
return Center(child: Text(provider.errorMessage!, style: const TextStyle(color: Colors.red)));
}

if (provider.items.isEmpty) {
return const Center(child: Text("No items"));
}

return ListView.builder(
itemCount: provider.items.length,
itemBuilder: (context, index) {
final todo = provider.items[index];
return ListTile(
leading: CircleAvatar(child: Text(todo.id.toString())),
title: Text(
todo.title,
style: TextStyle(
decoration: todo.completed ? TextDecoration.lineThrough : null,
),
),
trailing: Icon(
todo.completed ? Icons.check_circle : Icons.radio_button_unchecked,
color: todo.completed ? Colors.green : Colors.grey,
),
);
},
);
}
}
48 changes: 48 additions & 0 deletions task_manager_app/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,22 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
http:
dependency: "direct main"
description:
name: http
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
url: "https://pub.dev"
source: hosted
version: "1.6.0"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted
version: "4.1.2"
leak_tracker:
dependency: transitive
description:
Expand Down Expand Up @@ -131,6 +147,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.17.0"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
path:
dependency: transitive
description:
Expand All @@ -139,6 +163,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.1"
provider:
dependency: "direct main"
description:
name: provider
sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272"
url: "https://pub.dev"
source: hosted
version: "6.1.5+1"
sky_engine:
dependency: transitive
description: flutter
Expand Down Expand Up @@ -192,6 +224,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.10"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
version: "1.4.0"
vector_math:
dependency: transitive
description:
Expand All @@ -208,6 +248,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "15.0.2"
web:
dependency: transitive
description:
name: web
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
sdks:
dart: ">=3.9.0-0 <4.0.0"
flutter: ">=3.18.0-18.0.pre.54"
4 changes: 4 additions & 0 deletions task_manager_app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ environment:
dependencies:
flutter:
sdk: flutter
http: ^1.2.0
provider: ^6.1.1
cupertino_icons: ^1.0.6

dev_dependencies:
Expand All @@ -18,3 +20,5 @@ dev_dependencies:

flutter:
uses-material-design: true


3 changes: 2 additions & 1 deletion task_manager_app/test/widget_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
import 'package:task_manager_app/main.dart';


void main() {
testWidgets('App shows Task Manager title and welcome message',
(WidgetTester tester) async {
await tester.pumpWidget(const TaskManagerApp());
await tester.pumpWidget(const MyApp());

// AppBar title from HomePage.
expect(find.textContaining('Week 2'), findsOneWidget);
Expand Down
Loading