diff --git a/lib/config/colors.dart b/lib/config/colors.dart index f950949..775db80 100644 --- a/lib/config/colors.dart +++ b/lib/config/colors.dart @@ -2,24 +2,24 @@ import 'package:flutter/material.dart'; class AppColors { // dark theme colors - static const Color primaryDark = Colors.green; - static Color primaryDark500 = Colors.green.shade500; - static Color primaryDark800 = Colors.green.shade800; + static const Color primaryDark = Colors.purple; + static Color primaryDark500 = Colors.purple.shade500; + static Color primaryDark800 = Colors.purple.shade800; static const Color backgroundDark = Colors.black; - static Color scaffoldBackgroundDark = Colors.grey.shade900; + static Color scaffoldBackgroundDark = Color.fromARGB(255, 7, 8, 12); static const Color cardDark = Colors.black12; static const Color shadowDark = Colors.black; static const Color drawerBackgroundDark = Colors.black87; static const Color dialogBackgroundDark = Colors.grey; // light colors - static const Color primaryLight = Colors.green; - static Color primaryLight400 = Colors.green.shade400; - static Color primaryLight50 = Colors.green.shade50; + static const Color primaryLight = Colors.purple; + static Color primaryLight400 = Colors.purple.shade400; + static Color primaryLight50 = Colors.purple.shade50; static const Color backgroundLight = Colors.white; static const Color scaffoldBackgroundLight = Colors.white; static Color cardLight = Colors.grey.shade200; static Color shadowLight = Colors.grey.shade200; - static Color drawerBackgroundLight = Colors.green.shade50; - static Color dialogBackgroundLight = Colors.green.shade50; + static Color drawerBackgroundLight = Colors.purple.shade50; + static Color dialogBackgroundLight = Colors.purple.shade50; } diff --git a/lib/controllers/auth/signup_controller.dart b/lib/controllers/auth/signup_controller.dart index 4753914..baf9499 100644 --- a/lib/controllers/auth/signup_controller.dart +++ b/lib/controllers/auth/signup_controller.dart @@ -7,6 +7,7 @@ class SignUpController { final FirebaseAuth _auth = FirebaseAuth.instance; final ValueNotifier isLoading = ValueNotifier(false); + Future> signUp( BuildContext context, String email, String password) async { try { diff --git a/lib/controllers/common/event_controller.dart b/lib/controllers/common/event_controller.dart index 7b9c877..155f389 100644 --- a/lib/controllers/common/event_controller.dart +++ b/lib/controllers/common/event_controller.dart @@ -1,29 +1,80 @@ -import 'package:Organiser/models/common/event.dart'; -import 'package:flutter/material.dart'; +import 'package:Organiser/models/common/event_model.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; -class EventModel extends ChangeNotifier { - List events = []; +class EventController { + final FirebaseFirestore _firestore = FirebaseFirestore.instance; + String _parentCollection; - void addEvent(Event newEvent) { - events.add(newEvent); - notifyListeners(); + EventController(this._parentCollection); + + Future addEvent(String documentId, Event event) async { + try { + await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('events') + .add(event.toMap()); + } catch (e) { + print('Error adding event: $e'); + rethrow; + } + } + + Future updateEvent(String documentId, Event event) async { + try { + await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('events') + .doc(event.id) + .set(event.toMap()); + } catch (e) { + print('Error updating event: $e'); + rethrow; + } } - void updateEvent(Event updatedEvent) { - final index = events.indexWhere((event) => event.id == updatedEvent.id); - if (index != -1) { - events[index] = updatedEvent; - notifyListeners(); + Future deleteEvent(String documentId, String eventId) async { + try { + await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('events') + .doc(eventId) + .delete(); + } catch (e) { + print('Error deleting event: $e'); + rethrow; } } - void deleteEvent(String eventId) { - events.removeWhere((event) => event.id == eventId); - notifyListeners(); + Stream> getAllEvents(String documentId) { + return _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('events') + .snapshots() + .map((snapshot) => snapshot.docs + .map((doc) => Event.fromMap(doc.data(), doc.id)) + .toList()); } - Event? getEventById(String eventId) { - return events.firstWhere((event) => event.id == eventId); + Future getEventById(String documentId, String eventId) async { + try { + var docSnapshot = await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('events') + .doc(eventId) + .get(); + if (docSnapshot.exists) { + return Event.fromMap( + docSnapshot.data() as Map, eventId); + } + return null; + } catch (e) { + print('Error fetching event: $e'); + rethrow; + } } - } diff --git a/lib/controllers/common/food_controller.dart b/lib/controllers/common/food_controller.dart new file mode 100644 index 0000000..f2fd6c9 --- /dev/null +++ b/lib/controllers/common/food_controller.dart @@ -0,0 +1,98 @@ +import 'package:Organiser/models/common/food_model.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; + +class FoodController { + final FirebaseFirestore _firestore = FirebaseFirestore.instance; + + Future getFood(String marketId, String foodId) async { + try { + var docSnapshot = await _firestore + .collection('markets') + .doc(marketId) + .collection('foods') + .doc(foodId) + .get(); + if (docSnapshot.exists) { + return Food.fromJson(docSnapshot.data() as Map); + } + return null; + } catch (e) { + print('Error getting food: $e'); + rethrow; + } + } + + Future> getAllFoods(String marketId) async { + try { + var querySnapshot = await _firestore + .collection('markets') + .doc(marketId) + .collection('foods') + .get(); + return querySnapshot.docs + .map((doc) => Food.fromJson(doc.data())) + .toList(); + } catch (e) { + print('Error getting all foods: $e'); + rethrow; + } + } + + Stream> listenToFoods(String marketId) { + try { + return _firestore + .collection('markets') + .doc(marketId) + .collection('foods') + .snapshots() + .map((snapshot) => snapshot.docs + .map((doc) => Food.fromJson(doc.data())) + .toList()); + } catch (e) { + print('Error listening to foods: $e'); + rethrow; + } + } + + Future addFood(String marketId, Food food) async { + try { + await _firestore + .collection('markets') + .doc(marketId) + .collection('foods') + .doc(food.id) + .set(food.toJson()); + } catch (e) { + print('Error adding food: $e'); + rethrow; + } + } + + Future updateFood(String marketId, Food food) async { + try { + await _firestore + .collection('markets') + .doc(marketId) + .collection('foods') + .doc(food.id) + .update(food.toJson()); + } catch (e) { + print('Error updating food: $e'); + rethrow; + } + } + + Future deleteFood(String marketId, String foodId) async { + try { + await _firestore + .collection('markets') + .doc(marketId) + .collection('foods') + .doc(foodId) + .delete(); + } catch (e) { + print('Error deleting food: $e'); + rethrow; + } + } +} diff --git a/lib/controllers/common/goal_controller.dart b/lib/controllers/common/goal_controller.dart index e69de29..dfb1d40 100644 --- a/lib/controllers/common/goal_controller.dart +++ b/lib/controllers/common/goal_controller.dart @@ -0,0 +1,79 @@ +import 'package:Organiser/models/common/goal_model.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; + +class GoalController { + final FirebaseFirestore _firestore = FirebaseFirestore.instance; + String _parentCollection; + + GoalController(this._parentCollection); + + Future addGoal(String documentId, Goal goal) async { + try { + await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('goals') + .add(goal.toMap()); + } catch (e) { + print('Error adding goal: $e'); + rethrow; + } + } + + Future updateGoal(String documentId, Goal goal) async { + try { + await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('goals') + .doc(goal.id) + .set(goal.toMap()); + } catch (e) { + print('Error updating goal: $e'); + rethrow; + } + } + + Future deleteGoal(String documentId, String goalId) async { + try { + await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('goals') + .doc(goalId) + .delete(); + } catch (e) { + print('Error deleting goal: $e'); + rethrow; + } + } + + Stream> getAllGoals(String documentId) { + return _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('goals') + .snapshots() + .map((snapshot) => snapshot.docs + .map((doc) => Goal.fromMap(doc.data(), doc.id)) + .toList()); + } + + Future getGoalById(String documentId, String goalId) async { + try { + var docSnapshot = await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('goals') + .doc(goalId) + .get(); + if (docSnapshot.exists) { + return Goal.fromMap(docSnapshot.data() as Map, goalId); + } + return null; + } catch (e) { + print('Error fetching goal: $e'); + rethrow; + } + } +} diff --git a/lib/controllers/common/meal_controller.dart b/lib/controllers/common/meal_controller.dart index e69de29..3128fac 100644 --- a/lib/controllers/common/meal_controller.dart +++ b/lib/controllers/common/meal_controller.dart @@ -0,0 +1,79 @@ +import 'package:Organiser/models/common/meal_model.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; + +class MealController { + final FirebaseFirestore _firestore = FirebaseFirestore.instance; + String _parentCollection; + + MealController(this._parentCollection); + + Future addMeal(String documentId, Meal meal) async { + try { + await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('meals') + .add(meal.toMap()); + } catch (e) { + print('Error adding meal: $e'); + rethrow; + } + } + + Future updateMeal(String documentId, Meal meal) async { + try { + await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('meals') + .doc(meal.id) + .set(meal.toMap()); + } catch (e) { + print('Error updating meal: $e'); + rethrow; + } + } + + Future deleteMeal(String documentId, String mealId) async { + try { + await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('meals') + .doc(mealId) + .delete(); + } catch (e) { + print('Error deleting meal: $e'); + rethrow; + } + } + + Stream> getAllMeals(String documentId) { + return _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('meals') + .snapshots() + .map((snapshot) => snapshot.docs + .map((doc) => Meal.fromMap(doc.data(), doc.id)) + .toList()); + } + + Future getMealById(String documentId, String mealId) async { + try { + var docSnapshot = await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('meals') + .doc(mealId) + .get(); + if (docSnapshot.exists) { + return Meal.fromMap(docSnapshot.data() as Map, mealId); + } + return null; + } catch (e) { + print('Error fetching meal: $e'); + rethrow; + } + } +} diff --git a/lib/controllers/common/schedule_controller.dart b/lib/controllers/common/schedule_controller.dart index e69de29..179ad9e 100644 --- a/lib/controllers/common/schedule_controller.dart +++ b/lib/controllers/common/schedule_controller.dart @@ -0,0 +1,81 @@ +import 'package:Organiser/models/common/schedule_model.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; + +class ScheduleController { + final FirebaseFirestore _firestore = FirebaseFirestore.instance; + String _parentCollection; + + ScheduleController(this._parentCollection); + + Future addSchedule(String documentId, Schedule schedule) async { + try { + await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('schedules') + .add(schedule.toMap()); + } catch (e) { + print('Error adding schedule: $e'); + rethrow; + } + } + + Future updateSchedule(String documentId, Schedule schedule) async { + try { + await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('schedules') + .doc(schedule.id) + .set(schedule.toMap()); + } catch (e) { + print('Error updating schedule: $e'); + rethrow; + } + } + + Future deleteSchedule(String documentId, String scheduleId) async { + try { + await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('schedules') + .doc(scheduleId) + .delete(); + } catch (e) { + print('Error deleting schedule: $e'); + rethrow; + } + } + + Stream> getAllSchedules(String documentId) { + return _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('schedules') + .snapshots() + .map((snapshot) => snapshot.docs + .map((doc) => Schedule.fromMap(doc.data(), doc.id)) + .toList()); + } + + Future getScheduleById( + String documentId, String scheduleId) async { + try { + var docSnapshot = await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('schedules') + .doc(scheduleId) + .get(); + if (docSnapshot.exists) { + return Schedule.fromMap( + docSnapshot.data() as Map, scheduleId); + } + return null; + } catch (e) { + print('Error fetching schedule: $e'); + rethrow; + } + } +} diff --git a/lib/controllers/common/settings_controller.dart b/lib/controllers/common/settings_controller.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/controllers/common/social_settings_controller.dart b/lib/controllers/common/social_settings_controller.dart new file mode 100644 index 0000000..c6d8601 --- /dev/null +++ b/lib/controllers/common/social_settings_controller.dart @@ -0,0 +1,47 @@ +import 'package:Organiser/models/common/social_settings_model.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; + +class SocialSettingsController { + final FirebaseFirestore _firestore = FirebaseFirestore.instance; + String _parentCollection; + + SocialSettingsController(this._parentCollection); + + Future updateMemberSettings( + String documentId, String memberId, SocialSettings settings) async { + try { + await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('members') + .doc(memberId) + .collection('settings') + .doc('social') + .set(settings.toJson()); + } catch (e) { + print('Error updating member settings: $e'); + rethrow; + } + } + + Future getMemberSettings( + String documentId, String memberId) async { + try { + var docSnapshot = await _firestore + .collection(_parentCollection) + .doc(documentId) + .collection('members') + .doc(memberId) + .collection('settings') + .doc('social') + .get(); + if (docSnapshot.exists) { + return SocialSettings.fromJson(docSnapshot.data() as Map); + } + return null; + } catch (e) { + print('Error fetching member settings: $e'); + rethrow; + } + } +} diff --git a/lib/controllers/common/task_controller.dart b/lib/controllers/common/task_controller.dart index e69de29..3c02cf4 100644 --- a/lib/controllers/common/task_controller.dart +++ b/lib/controllers/common/task_controller.dart @@ -0,0 +1,80 @@ +import 'package:Organiser/models/common/task_model.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; + +class TaskController { + final FirebaseFirestore _firestore = FirebaseFirestore.instance; + final String parentCollection; + final String ownerId; + + TaskController(this.parentCollection, this.ownerId); + + Future addTask(Task task) async { + try { + await _firestore + .collection(parentCollection) + .doc(ownerId) + .collection('tasks') + .add(task.toMap()); + } catch (e) { + print('Error adding task: $e'); + rethrow; + } + } + + Future updateTask(Task task) async { + try { + await _firestore + .collection(parentCollection) + .doc(ownerId) + .collection('tasks') + .doc(task.id) + .set(task.toMap()); + } catch (e) { + print('Error updating task: $e'); + rethrow; + } + } + + Future deleteTask(String taskId) async { + try { + await _firestore + .collection(parentCollection) + .doc(ownerId) + .collection('tasks') + .doc(taskId) + .delete(); + } catch (e) { + print('Error deleting task: $e'); + rethrow; + } + } + + Stream> getAllTasks() { + return _firestore + .collection(parentCollection) + .doc(ownerId) + .collection('tasks') + .snapshots() + .map((snapshot) => snapshot.docs + .map((doc) => Task.fromMap(doc.data(), doc.id)) + .toList()); + } + + Future getTaskById(String taskId) async { + try { + var docSnapshot = await _firestore + .collection(parentCollection) + .doc(ownerId) + .collection('tasks') + .doc(taskId) + .get(); + if (docSnapshot.exists) { + return Task.fromMap(docSnapshot.data() as Map, taskId); + } + return null; + } catch (e) { + print('Error fetching task: $e'); + rethrow; + } + } +} diff --git a/lib/controllers/common/user_settings_controller.dart b/lib/controllers/common/user_settings_controller.dart new file mode 100644 index 0000000..76b5580 --- /dev/null +++ b/lib/controllers/common/user_settings_controller.dart @@ -0,0 +1,35 @@ +import 'package:Organiser/models/common/user_settings_model.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; + +class UserSettingsController { + final FirebaseFirestore _firestore = FirebaseFirestore.instance; + String _parentCollection; + + UserSettingsController(this._parentCollection); + + Future updateSettings(String documentId, UserSettings settings) async { + try { + await _firestore + .collection(_parentCollection) + .doc(documentId) + .set(settings.toMap()); + } catch (e) { + print('Error updating settings: $e'); + rethrow; // Rethrow the error for handling in the UI + } + } + + Future getSettings(String documentId) async { + try { + var docSnapshot = + await _firestore.collection(_parentCollection).doc(documentId).get(); + if (docSnapshot.exists) { + return UserSettings.fromMap(docSnapshot.data() as Map); + } + return null; + } catch (e) { + print('Error fetching settings: $e'); + rethrow; // Rethrow the error for handling in the UI + } + } +} diff --git a/lib/controllers/market_conroller.dart b/lib/controllers/market_conroller.dart new file mode 100644 index 0000000..79c11f6 --- /dev/null +++ b/lib/controllers/market_conroller.dart @@ -0,0 +1,66 @@ +import 'package:Organiser/models/market_model.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; + +class MarketController { + final FirebaseFirestore _firestore = FirebaseFirestore.instance; + + Future> getAllMarkets() async { + try { + QuerySnapshot querySnapshot = + await _firestore.collection('markets').get(); + return querySnapshot.docs.map((doc) { + return Market.fromJson(doc.data() as Map); + }).toList(); + } catch (e) { + print('Error getting all markets: $e'); + rethrow; + } + } + + Future addMarket(Market market) async { + try { + await _firestore + .collection('markets') + .doc(market.id) + .set(market.toJson()); + } catch (e) { + print('Error adding market: $e'); + rethrow; + } + } + + Future getMarket(String marketId) async { + try { + var docSnapshot = + await _firestore.collection('markets').doc(marketId).get(); + if (docSnapshot.exists) { + return Market.fromJson(docSnapshot.data() as Map); + } + return null; + } catch (e) { + print('Error getting market: $e'); + rethrow; + } + } + + Future updateMarket(Market market) async { + try { + await _firestore + .collection('markets') + .doc(market.id) + .update(market.toJson()); + } catch (e) { + print('Error updating market: $e'); + rethrow; + } + } + + Future deleteMarket(String marketId) async { + try { + await _firestore.collection('markets').doc(marketId).delete(); + } catch (e) { + print('Error deleting market: $e'); + rethrow; + } + } +} diff --git a/lib/controllers/user_controller.dart b/lib/controllers/user_controller.dart index 522b10e..9bf59f1 100644 --- a/lib/controllers/user_controller.dart +++ b/lib/controllers/user_controller.dart @@ -1,4 +1,4 @@ -import 'package:Organiser/models/user.dart'; +import 'package:Organiser/models/user_model.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; @@ -26,4 +26,4 @@ class UserController { Future deleteUser(String userId) async { await _firestore.collection('users').doc(userId).delete(); } -} +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index acd58f8..04b972e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,7 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'views/services/user_provider.dart'; - + void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -49,10 +49,7 @@ class _OrganiserAppState extends State { themeProvider.themeData.brightness == Brightness.dark ? Brightness.light : Brightness.dark, - systemNavigationBarColor: - themeProvider.themeData.brightness == Brightness.dark - ? Colors.black - : Colors.white, + systemNavigationBarColor: themeProvider.themeData.scaffoldBackgroundColor, statusBarIconBrightness: themeProvider.themeData.brightness == Brightness.dark ? Brightness.light @@ -61,6 +58,7 @@ class _OrganiserAppState extends State { ? Brightness.light : Brightness.dark, systemStatusBarContrastEnforced: false, + systemNavigationBarDividerColor: themeProvider.themeData.scaffoldBackgroundColor, )); return MaterialApp( theme: themeProvider.themeData, diff --git a/lib/models/classes/do_day.dart b/lib/models/classes/do_day.dart new file mode 100644 index 0000000..03fe50a --- /dev/null +++ b/lib/models/classes/do_day.dart @@ -0,0 +1,107 @@ +import 'package:Organiser/models/enums/time_enums.dart'; + +class DoDay { + DateTime? tangibleValue; + + DoDay({this.tangibleValue}); + + factory DoDay.fromEnum(DoDayEnum day, {DayOfWeek? dayName}) { + switch (day) { + case DoDayEnum.today: + return DoDay(tangibleValue: DateTime.now()); + case DoDayEnum.tomorrow: + return DoDay(tangibleValue: DateTime.now().add(Duration(days: 1))); + case DoDayEnum.weekDay: + if (dayName != null) { + return DoDay(tangibleValue: getDateForDay(dayName)); + } + return DoDay(); + default: + return DoDay(); + } + } + + dynamic getEnumValue() { + return tangibleValue; + } + + dynamic getTangibleValue() { + return tangibleValue; + } + + void setCustomValue(dynamic value) { + if (value is DateTime) { + tangibleValue = value; + } else { + tangibleValue = null; + } + } + + static DateTime getDateForDay(DayOfWeek dayName) { + final int targetDayIndex = dayName.index + 1; + final DateTime now = DateTime.now(); + final int currentDayIndex = now.weekday; + final int daysDifference = (targetDayIndex - currentDayIndex + 7) % 7; + final DateTime targetDate = now.add(Duration(days: daysDifference)); + return targetDate; + } + + static String formatDate(DateTime date) { + return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}'; + } + + String toText() { + if (tangibleValue == null) { + return 'No date set'; + } + + DateTime now = DateTime.now(); + DateTime today = DateTime(now.year, now.month, now.day); + DateTime targetDate = DateTime(tangibleValue!.year, tangibleValue!.month, tangibleValue!.day); + + if (targetDate == today) { + return 'Today'; + } else if (targetDate == today.add(Duration(days: 1))) { + return 'Tomorrow'; + } else if (targetDate == today.subtract(Duration(days: 1))) { + return 'Yesterday'; + } else if (targetDate.isAfter(today.subtract(Duration(days: 7))) && targetDate.isBefore(today)) { + return 'Last ${dayOfWeek(targetDate.weekday)}'; + } else if (targetDate.isAfter(today) && targetDate.isBefore(today.add(Duration(days: 7)))) { + return 'This ${dayOfWeek(targetDate.weekday)}'; + } else if (targetDate.isAfter(today.add(Duration(days: 7))) && targetDate.isBefore(today.add(Duration(days: 14)))) { + return 'Next ${dayOfWeek(targetDate.weekday)}'; + } else if (targetDate.month == now.month + 1 && targetDate.year == now.year) { + return 'Next month'; + } else if (targetDate.year == now.year + 1) { + return 'Next year'; + } else if (targetDate.month == now.month - 1 && targetDate.year == now.year) { + return 'Last month'; + } else if (targetDate.year == now.year - 1) { + return 'Last year'; + } else { + return 'On ${formatDate(tangibleValue!)}'; + } + } + + String dayOfWeek(int weekday) { + switch (weekday) { + case DateTime.monday: + return 'Monday'; + case DateTime.tuesday: + return 'Tuesday'; + case DateTime.wednesday: + return 'Wednesday'; + case DateTime.thursday: + return 'Thursday'; + case DateTime.friday: + return 'Friday'; + case DateTime.saturday: + return 'Saturday'; + case DateTime.sunday: + return 'Sunday'; + default: + return ''; + } + } +} diff --git a/lib/models/classes/do_time.dart b/lib/models/classes/do_time.dart new file mode 100644 index 0000000..d5318cc --- /dev/null +++ b/lib/models/classes/do_time.dart @@ -0,0 +1,63 @@ +import 'package:Organiser/models/enums/time_enums.dart'; +import 'package:flutter/material.dart'; + +class DoTime { + TimeOfDay? tangibleValue; + + DoTime({this.tangibleValue}); + + factory DoTime.fromEnum(DoTimeEnum time) { + switch (time) { + case DoTimeEnum.morning: + return DoTime(tangibleValue: TimeOfDay(hour: 8, minute: 0)); + case DoTimeEnum.noon: + return DoTime(tangibleValue: TimeOfDay(hour: 12, minute: 0)); + case DoTimeEnum.afternoon: + return DoTime(tangibleValue: TimeOfDay(hour: 14, minute: 0)); + case DoTimeEnum.evening: + return DoTime(tangibleValue: TimeOfDay(hour: 19, minute: 0)); + case DoTimeEnum.night: + return DoTime(tangibleValue: TimeOfDay(hour: 21, minute: 0)); + case DoTimeEnum.midnight: + return DoTime(tangibleValue: TimeOfDay(hour: 0, minute: 0)); + case DoTimeEnum.none: + return DoTime(); + default: + return DoTime(); + } + } + + TimeOfDay? getEnumValue() { + return tangibleValue; + } + + TimeOfDay? getTangibleValue() { + return tangibleValue; + } + + void setCustomValue(TimeOfDay value) { + tangibleValue = value; + } + + String toText(BuildContext context) { + if (tangibleValue == null) { + return 'No time set'; + } + + if (tangibleValue == TimeOfDay(hour: 8, minute: 0)) { + return 'Morning'; + } else if (tangibleValue == TimeOfDay(hour: 12, minute: 0)) { + return 'Noon'; + } else if (tangibleValue == TimeOfDay(hour: 14, minute: 0)) { + return 'Afternoon'; + } else if (tangibleValue == TimeOfDay(hour: 19, minute: 0)) { + return 'Evening'; + } else if (tangibleValue == TimeOfDay(hour: 21, minute: 0)) { + return 'Night'; + } else if (tangibleValue == TimeOfDay(hour: 0, minute: 0)) { + return 'Midnight'; + } else { + return 'At ${tangibleValue!.format(context)}'; + } + } +} diff --git a/lib/models/classes/repeat_interval.dart b/lib/models/classes/repeat_interval.dart new file mode 100644 index 0000000..34f2c3a --- /dev/null +++ b/lib/models/classes/repeat_interval.dart @@ -0,0 +1,70 @@ +import 'package:Organiser/models/enums/time_enums.dart'; + +class RepeatInterval { + RepeatIntervalEnum type; + int every; + + RepeatInterval({ + required this.type, + this.every = 1, + }) { + if (every <= 0) { + throw ArgumentError('Repeat interval must be greater than zero.'); + } + } + + // Convert RepeatInterval object to a map (for Firestore or other storage) + Map toMap() { + return { + 'type': type.toString().split('.').last, + 'every': every, + }; + } + + // Create RepeatInterval object from map (e.g., Firestore document snapshot data) + factory RepeatInterval.fromMap(Map map) { + return RepeatInterval( + type: _parseRepeatIntervalEnum(map['type']), + every: map['every'] ?? 1, + ); + } + + // Utility function to convert string to RepeatIntervalEnum + static RepeatIntervalEnum _parseRepeatIntervalEnum(String typeString) { + switch (typeString.toLowerCase()) { + case 'daily': + return RepeatIntervalEnum.daily; + case 'weekly': + return RepeatIntervalEnum.weekly; + case 'monthly': + return RepeatIntervalEnum.monthly; + case 'yearly': + return RepeatIntervalEnum.yearly; + default: + throw ArgumentError('Unknown RepeatIntervalEnum type: $typeString'); + } + } + + RepeatIntervalEnum getType() { + return type; + } + + int getEvery() { + return every; + } + + void setType(RepeatIntervalEnum newType) { + type = newType; + } + + void setEvery(int newEvery) { + if (newEvery <= 0) { + throw ArgumentError('Repeat interval must be greater than zero.'); + } + every = newEvery; + } + + String toText() { + return 'Every $every ${type.toString().split('.').last}'; + } +} diff --git a/lib/models/classes/repeat_type.dart b/lib/models/classes/repeat_type.dart new file mode 100644 index 0000000..4d7a912 --- /dev/null +++ b/lib/models/classes/repeat_type.dart @@ -0,0 +1,83 @@ +import 'package:Organiser/models/enums/time_enums.dart'; + +class RepeatType { + RepeatTypeEnum type; + dynamic value; + + RepeatType({ + required this.type, + this.value, + }) { + if (type == RepeatTypeEnum.repeatCount && (value == null || value <= 1)) { + throw ArgumentError('Repeat count must be greater than one.'); + } + if (type == RepeatTypeEnum.repeatUntil && value == null) { + throw ArgumentError('Repeat until date must be provided.'); + } + } + + // Convert RepeatType object to a map (for Firestore or other storage) + Map toMap() { + return { + 'type': type.toString().split('.').last, + 'value': value, + }; + } + + // Create RepeatType object from map (e.g., Firestore document snapshot data) + factory RepeatType.fromMap(Map map) { + return RepeatType( + type: _parseRepeatTypeEnum(map['type']), + value: map['value'], + ); + } + + // Utility function to convert string to RepeatTypeEnum + static RepeatTypeEnum _parseRepeatTypeEnum(String typeString) { + switch (typeString.toLowerCase()) { + case 'repeatuntil': + return RepeatTypeEnum.repeatUntil; + case 'repeatcount': + return RepeatTypeEnum.repeatCount; + case 'infinite': + return RepeatTypeEnum.infinite; + default: + throw ArgumentError('Unknown RepeatTypeEnum type: $typeString'); + } + } + + RepeatTypeEnum getType() { + return type; + } + + dynamic getValue() { + return value; + } + + void setType(RepeatTypeEnum newType) { + type = newType; + } + + void setValue(dynamic newValue) { + if (type == RepeatTypeEnum.repeatCount && (newValue == null || newValue <= 1)) { + throw ArgumentError('Repeat count must be greater than one.'); + } + if (type == RepeatTypeEnum.repeatUntil && newValue == null) { + throw ArgumentError('Repeat until date must be provided.'); + } + value = newValue; + } + + String toText() { + switch (type) { + case RepeatTypeEnum.repeatUntil: + return 'Repeat until ${value.toString()}'; + case RepeatTypeEnum.repeatCount: + return 'Repeat ${value.toString()} times'; + case RepeatTypeEnum.infinite: + return 'Repeat indefinitely'; + default: + return 'No repeat type'; + } + } +} diff --git a/lib/models/common/event.dart b/lib/models/common/event_model.dart similarity index 57% rename from lib/models/common/event.dart rename to lib/models/common/event_model.dart index d982706..69376c3 100644 --- a/lib/models/common/event.dart +++ b/lib/models/common/event_model.dart @@ -1,15 +1,15 @@ -import 'package:Organiser/models/common/meal.dart'; +import 'package:Organiser/models/enums/event_enums.dart'; import 'package:flutter/material.dart'; class Event { - String id = ""; + String id; String priority; String title; String notes; String category; List tags; String photoURL; - List> dateAndTime; + List>> dateAndTime; bool isRepeating; List> repetition; List> location; @@ -18,6 +18,7 @@ class Event { String timezone; Event({ + required this.id, required this.title, required this.notes, required this.priority, @@ -30,28 +31,40 @@ class Event { required this.location, required this.ticketCost, required this.numberOfTickets, - required this.timezone, + required this.timezone, }); - // Factory constructor to create an Event instance from a Firebase snapshot factory Event.fromMap(Map data, String documentId) { return Event( + id: documentId, title: data['title'], priority: data['priority'], notes: data['description'], category: data['category'], tags: List.from(data['tags']), photoURL: data['photoURL'], - dateAndTime: List>.from(data['dateAndTime']), + dateAndTime: (data['dateAndTime'] as List).map((entry) { + return (entry as Map).map((key, value) { + return MapEntry( + DateTime.parse(key), + (value as Map).map((startTimeKey, startTimeValue) { + return MapEntry( + TimeOfDay.fromDateTime(DateTime.parse(startTimeKey)), + TimeOfDay.fromDateTime(DateTime.parse(startTimeValue)), + ); + }), + ); + }); + }).toList(), isRepeating: data['isRepeating'], repetition: List>.from(data['repetition']), location: List>.from(data['location']), ticketCost: data['ticketCost'], - numberOfTickets: data['numberOfTickets'], timezone: data['timezone'], + numberOfTickets: data['numberOfTickets'], + timezone: data['timezone'], ); } - // Method to convert Event instance to a map for Firebase Map toMap() { return { 'title': title, @@ -60,7 +73,19 @@ class Event { 'category': category, 'tags': tags, 'photoURL': photoURL, - 'dateAndTime': dateAndTime, + 'dateAndTime': dateAndTime.map((entry) { + return entry.map((key, value) { + return MapEntry( + key.toIso8601String(), + value.map((startTimeKey, startTimeValue) { + return MapEntry( + startTimeKey, + startTimeValue, + ); + }), + ); + }); + }).toList(), 'isRepeating': isRepeating, 'repetition': repetition, 'location': location, @@ -70,12 +95,3 @@ class Event { }; } } - -// ignore: unused_element -TimeOfDay _convertMapToTimeOfDay(Map timeMap) { - // Assuming 'hour' and 'minute' are the keys in your Firestore data - int hour = timeMap['hour']; - int minute = timeMap['minute']; - return TimeOfDay(hour: hour, minute: minute); -} - diff --git a/lib/models/common/food_model.dart b/lib/models/common/food_model.dart new file mode 100644 index 0000000..6a4f690 --- /dev/null +++ b/lib/models/common/food_model.dart @@ -0,0 +1,40 @@ +class Food { + String id; + String name; + String type; + double price; + String content; + List ingredients; + + Food({ + required this.id, + required this.name, + required this.type, + required this.price, + required this.content, + required this.ingredients, + + }); + + factory Food.fromJson(Map json) { + return Food( + id: json['id'], + name: json['name'], + type: json['type'], + price: json['price'].toDouble(), + content: json['content'], + ingredients: List.from(json['ingredients']), + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'type': type, + 'price': price, + 'content': content, + 'ingredients': ingredients, + }; + } +} diff --git a/lib/models/common/goal.dart b/lib/models/common/goal.dart deleted file mode 100644 index ffac56d..0000000 --- a/lib/models/common/goal.dart +++ /dev/null @@ -1,100 +0,0 @@ -import 'package:cloud_firestore/cloud_firestore.dart'; - -enum ReferenceType { - task, - event, - schedule, - meal, -} - -class Goal { - String id; // Unique identifier for the goal - String title; - String description; - String timeframe; - String category; - int priority; - Map> references; - - // Constructor - Goal({ - required this.id, - required this.title, - required this.description, - required this.timeframe, - required this.category, - required this.priority, - required this.references, - }); - - // Factory constructor to create a Goal instance from a Firebase snapshot - factory Goal.fromMap(Map data, String documentId) { - return Goal( - id: documentId, - title: data['title'], - description: data['description'], - timeframe: data['timeframe'], - category: data['category'], - priority: data['priority'], - references: _convertReferences(data['references']), - ); - } - - // Method to convert Goal instance to a map for Firebase - Map toMap() { - return { - 'title': title, - 'description': description, - 'timeframe': timeframe, - 'category': category, - 'priority': priority, - 'references': _convertReferencesToMap(references), - }; - } - - // Helper method to convert Firestore references to a map for Firebase - static Map> _convertReferencesToMap( - Map> references) { - final Map> referencesMap = {}; - - references.forEach((type, refs) { - final List refIds = refs.map((ref) => ref.id).toList(); - referencesMap[type.toString().split('.').last] = refIds; - }); - - return referencesMap; - } - - // Helper method to convert map of reference IDs to Firestore references - static Map> _convertReferences( - Map referencesMap) { - final Map> references = {}; - - referencesMap.forEach((typeString, refIds) { - final type = _getReferenceTypeFromString(typeString); - final List refs = (refIds as List) - .map( - (id) => FirebaseFirestore.instance.collection(typeString).doc(id)) - .toList(); - references[type] = refs; - }); - - return references; - } - - // Helper method to convert string to ReferenceType enum - static ReferenceType _getReferenceTypeFromString(String typeString) { - switch (typeString.toLowerCase()) { - case 'task': - return ReferenceType.task; - case 'event': - return ReferenceType.event; - case 'schedule': - return ReferenceType.schedule; - case 'meal': - return ReferenceType.meal; - default: - throw ArgumentError('Invalid ReferenceType: $typeString'); - } - } -} diff --git a/lib/models/common/goal_model.dart b/lib/models/common/goal_model.dart new file mode 100644 index 0000000..9847fcc --- /dev/null +++ b/lib/models/common/goal_model.dart @@ -0,0 +1,62 @@ +class Goal { + String id; + String title; + String description; + String timeframe; + String category; + int priority; + List tags; + List> media; + List tasks; + List meals; + List schedules; + List events; + + Goal({ + required this.id, + required this.title, + required this.description, + required this.timeframe, + required this.category, + required this.priority, + this.tags = const [], + this.media = const [], + this.tasks = const [], + this.meals = const [], + this.schedules = const [], + this.events = const [], + }); + + factory Goal.fromMap(Map data, String documentId) { + return Goal( + id: documentId, + title: data['title'], + description: data['description'], + timeframe: data['timeframe'], + category: data['category'], + priority: data['priority'], + tags: List.from(data['tags'] ?? []), + media: List>.from(data['media'] ?? []), + tasks: List.from(data['tasks'] ?? []), + meals: List.from(data['meals'] ?? []), + schedules: List.from(data['schedules'] ?? []), + events: List.from(data['events'] ?? []), + ); + } + + Map toMap() { + return { + 'title': title, + 'description': description, + 'timeframe': timeframe, + 'category': category, + 'priority': priority, + 'tags': tags, + 'media': media, + 'tasks': tasks, + 'meals': meals, + 'schedules': schedules, + 'events': events, + }; + } +} diff --git a/lib/models/common/meal.dart b/lib/models/common/meal.dart deleted file mode 100644 index 55e0c1f..0000000 --- a/lib/models/common/meal.dart +++ /dev/null @@ -1,105 +0,0 @@ -enum MealType { - fastFood, - breakfast, - lunch, - supper, - snack, -} - -enum RepeatFrequency { - daily, - weekly, - monthly, -} - -class Meal { - String id; // Unique identifier for the meal - String title; - String description; - Map nutrients; // Map of nutrients and their values - int calories; - MealType type; - List contents; // List of ingredients or contents - bool repeat; - RepeatFrequency repeatFrequency; - double cost; - - // Constructor - Meal({ - required this.id, - required this.title, - required this.description, - required this.nutrients, - required this.calories, - required this.type, - required this.contents, - required this.repeat, - required this.repeatFrequency, - required this.cost, - }); - - // Factory constructor to create a Meal instance from a Firebase snapshot - factory Meal.fromMap(Map data, String documentId) { - return Meal( - id: documentId, - title: data['title'], - description: data['description'], - nutrients: Map.from(data['nutrients']), - calories: data['calories'], - type: _getMealTypeFromString(data['type']), - contents: List.from(data['contents']), - repeat: data['repeat'], - repeatFrequency: _getRepeatFrequencyFromString(data['repeatFrequency']), - cost: data['cost'].toDouble(), - ); - } - - // Method to convert Meal instance to a map for Firebase - Map toMap() { - return { - 'title': title, - 'description': description, - 'nutrients': nutrients, - 'calories': calories, - 'type': type.toString().split('.').last, // Convert enum to string - 'contents': contents, - 'repeat': repeat, - 'repeatFrequency': - repeatFrequency.toString().split('.').last, // Convert enum to string - 'cost': cost, - }; - } - - // Helper method to convert string to MealType enum - static MealType _getMealTypeFromString(String mealTypeString) { - switch (mealTypeString.toLowerCase()) { - case 'fastfood': - return MealType.fastFood; - case 'breakfast': - return MealType.breakfast; - case 'lunch': - return MealType.lunch; - case 'supper': - return MealType.supper; - case 'snack': - return MealType.snack; - default: - return MealType.fastFood; // Default to fast food if not recognized - } - } - - // Helper method to convert string to RepeatFrequency enum - static RepeatFrequency _getRepeatFrequencyFromString( - String repeatFrequencyString) { - switch (repeatFrequencyString.toLowerCase()) { - case 'daily': - return RepeatFrequency.daily; - case 'weekly': - return RepeatFrequency.weekly; - case 'monthly': - return RepeatFrequency.monthly; - default: - return RepeatFrequency.daily; // Default to daily if not recognized - } - } -} diff --git a/lib/models/common/meal_model.dart b/lib/models/common/meal_model.dart new file mode 100644 index 0000000..cda712d --- /dev/null +++ b/lib/models/common/meal_model.dart @@ -0,0 +1,58 @@ +import 'package:Organiser/models/classes/repeat_interval.dart'; +import 'package:Organiser/models/enums/meal_enums.dart'; + +class Meal { + String id; + String title; + String description; + Map nutrients; + int calories; + MealType type; + List contents; + bool repeat; + RepeatInterval repeatFrequency; + double cost; + + Meal({ + required this.id, + required this.title, + required this.description, + required this.nutrients, + required this.calories, + required this.type, + required this.contents, + required this.repeat, + required this.repeatFrequency, + required this.cost, + }); + + factory Meal.fromMap(Map data, String documentId) { + return Meal( + id: documentId, + title: data['title'], + description: data['description'], + nutrients: Map.from(data['nutrients']), + calories: data['calories'], + type: MealType.values + .firstWhere((e) => e.toString().split('.').last == data['type']), + contents: List.from(data['contents']), + repeat: data['repeat'], + repeatFrequency: data['repeatFrequency'], + cost: data['cost'].toDouble(), + ); + } + + Map toMap() { + return { + 'title': title, + 'description': description, + 'nutrients': nutrients, + 'calories': calories, + 'type': type.toString().split('.').last, + 'contents': contents, + 'repeat': repeat, + 'repeatFrequency': repeatFrequency.toString().split('.').last, + 'cost': cost, + }; + } +} diff --git a/lib/models/common/media_model.dart b/lib/models/common/media_model.dart new file mode 100644 index 0000000..3d84a85 --- /dev/null +++ b/lib/models/common/media_model.dart @@ -0,0 +1,23 @@ +class MediaType { + final String url; + final String type; // This can be a file extension or MIME type + + MediaType({ + required this.url, + required this.type, + }); + + factory MediaType.fromJson(Map json) { + return MediaType( + url: json['url'] ?? '', + type: json['type'] ?? '', + ); + } + + Map toJson() { + return { + 'url': url, + 'type': type, + }; + } +} diff --git a/lib/models/common/schedule.dart b/lib/models/common/schedule.dart deleted file mode 100644 index 5a5059e..0000000 --- a/lib/models/common/schedule.dart +++ /dev/null @@ -1,87 +0,0 @@ -import 'package:cloud_firestore/cloud_firestore.dart'; - -enum RepeatType { - daily, - weekly, - monthly, - yearly, - custom, -} - -class Schedule { - String id; // Unique identifier for the schedule - String title; - String description; - List doDays; // List of days of the week (0 - 6, where 0 is Sunday) - DateTime? customDate; // Custom date if repeat type is custom - Duration duration; - bool repeat; - RepeatType repeatType; - int priority; - String category; - - // Constructor - Schedule({ - required this.id, - required this.title, - required this.description, - required this.doDays, - this.customDate, - required this.duration, - required this.repeat, - required this.repeatType, - required this.priority, - required this.category, - }); - - // Factory constructor to create a Schedule instance from a Firebase snapshot - factory Schedule.fromMap(Map data, String documentId) { - return Schedule( - id: documentId, - title: data['title'], - description: data['description'], - doDays: List.from(data['doDays']), - customDate: (data['customDate'] as Timestamp).toDate(), - duration: Duration(minutes: data['duration']), - repeat: data['repeat'], - repeatType: _getRepeatTypeFromString(data['repeatType']), - priority: data['priority'], - category: data['category'], - ); - } - - // Method to convert Schedule instance to a map for Firebase - Map toMap() { - return { - 'title': title, - 'description': description, - 'doDays': doDays, - 'customDate': - customDate, // You may need to convert this to a Firestore Timestamp if needed - 'duration': duration.inMinutes, - 'repeat': repeat, - 'repeatType': - repeatType.toString().split('.').last, // Convert enum to string - 'priority': priority, - 'category': category, - }; - } - - // Helper method to convert string to RepeatType enum - static RepeatType _getRepeatTypeFromString(String repeatTypeString) { - switch (repeatTypeString.toLowerCase()) { - case 'daily': - return RepeatType.daily; - case 'weekly': - return RepeatType.weekly; - case 'monthly': - return RepeatType.monthly; - case 'yearly': - return RepeatType.yearly; - case 'custom': - return RepeatType.custom; - default: - return RepeatType.daily; // Default to daily if not recognized - } - } -} diff --git a/lib/models/common/schedule_model.dart b/lib/models/common/schedule_model.dart new file mode 100644 index 0000000..9fc950d --- /dev/null +++ b/lib/models/common/schedule_model.dart @@ -0,0 +1,57 @@ +import 'package:Organiser/models/classes/repeat_interval.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; + +class Schedule { + String id; + String title; + String description; + List doDays; + DateTime? customDate; + Duration duration; + bool repeat; + RepeatInterval repeatType; + int priority; + String category; + + Schedule({ + required this.id, + required this.title, + required this.description, + required this.doDays, + this.customDate, + required this.duration, + required this.repeat, + required this.repeatType, + required this.priority, + required this.category, + }); + + factory Schedule.fromMap(Map data, String documentId) { + return Schedule( + id: documentId, + title: data['title'], + description: data['description'], + doDays: List.from(data['doDays']), + customDate: (data['customDate'] as Timestamp?)?.toDate(), + duration: Duration(minutes: data['duration']), + repeat: data['repeat'], + repeatType: data['repeatType'], + priority: data['priority'], + category: data['category'], + ); + } + + Map toMap() { + return { + 'title': title, + 'description': description, + 'doDays': doDays, + 'customDate': customDate, + 'duration': duration.inMinutes, + 'repeat': repeat, + 'repeatType': repeatType.toString().split('.').last, + 'priority': priority, + 'category': category, + }; + } +} diff --git a/lib/models/common/settings.dart b/lib/models/common/settings.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/models/common/social_settings_model.dart b/lib/models/common/social_settings_model.dart new file mode 100644 index 0000000..b53785f --- /dev/null +++ b/lib/models/common/social_settings_model.dart @@ -0,0 +1,31 @@ +class SocialSettings { + bool receiveNotifications; + bool allowEmailNotifications; + bool allowPushNotifications; + bool allowMessageNotifications; + + SocialSettings({ + required this.receiveNotifications, + required this.allowEmailNotifications, + required this.allowPushNotifications, + required this.allowMessageNotifications, + }); + + factory SocialSettings.fromJson(Map json) { + return SocialSettings( + receiveNotifications: json['receiveNotifications'] ?? true, + allowEmailNotifications: json['allowEmailNotifications'] ?? true, + allowPushNotifications: json['allowPushNotifications'] ?? true, + allowMessageNotifications: json['allowMessageNotifications'] ?? true, + ); + } + + Map toJson() { + return { + 'receiveNotifications': receiveNotifications, + 'allowEmailNotifications': allowEmailNotifications, + 'allowPushNotifications': allowPushNotifications, + 'allowMessageNotifications': allowMessageNotifications, + }; + } +} diff --git a/lib/models/common/task.dart b/lib/models/common/task.dart deleted file mode 100644 index 9374866..0000000 --- a/lib/models/common/task.dart +++ /dev/null @@ -1,113 +0,0 @@ -import 'package:cloud_firestore/cloud_firestore.dart'; - -enum RepeatInterval { - daily, - weekly, - monthly, - yearly, -} - -enum DoTime { - morning, - afternoon, - evening, - custom, -} - -class Task { - String id; // Unique identifier for the task - String title; - String description; - Map subtasks; // Map of subtask names to their completion status - DateTime doDay; // Date when the task should be done - DoTime - doTime; // Time when the task should be done (morning, afternoon, evening, custom) - int priority; // Priority level (1 - 3) - String category; - bool repeat; // Whether the task should be repeated - RepeatInterval - repeatInterval; // Interval for repeating (daily, weekly, monthly, yearly) - int repeatCount; // How many times to repeat - - // Constructor - Task({ - required this.id, - required this.title, - required this.description, - required this.subtasks, - required this.doDay, - required this.doTime, - required this.priority, - required this.category, - required this.repeat, - required this.repeatInterval, - required this.repeatCount, - }); - - // Factory constructor to create a Task instance from a Firebase snapshot - factory Task.fromMap(Map data, String documentId) { - return Task( - id: documentId, - title: data['title'], - description: data['description'], - subtasks: Map.from(data['subtasks']), - doDay: (data['doDay'] as Timestamp) - .toDate(), // Assuming Firestore Timestamp is used - doTime: _getDoTimeFromString(data['doTime']), - priority: data['priority'], - category: data['category'], - repeat: data['repeat'], - repeatInterval: _getRepeatIntervalFromString(data['repeatInterval']), - repeatCount: data['repeatCount'], - ); - } - - // Method to convert Task instance to a map for Firebase - Map toMap() { - return { - 'title': title, - 'description': description, - 'subtasks': subtasks, - 'doDay': - doDay, // You may need to convert this to a Firestore Timestamp if needed - 'doTime': doTime.toString().split('.').last, // Convert enum to string - 'priority': priority, - 'category': category, - 'repeat': repeat, - 'repeatInterval': - repeatInterval.toString().split('.').last, // Convert enum to string - 'repeatCount': repeatCount, - }; - } - - // Helper method to convert string to DoTime enum - static DoTime _getDoTimeFromString(String doTimeString) { - switch (doTimeString.toLowerCase()) { - case 'morning': - return DoTime.morning; - case 'afternoon': - return DoTime.afternoon; - case 'evening': - return DoTime.evening; - default: - return DoTime.custom; - } - } - - // Helper method to convert string to RepeatInterval enum - static RepeatInterval _getRepeatIntervalFromString( - String repeatIntervalString) { - switch (repeatIntervalString.toLowerCase()) { - case 'daily': - return RepeatInterval.daily; - case 'weekly': - return RepeatInterval.weekly; - case 'monthly': - return RepeatInterval.monthly; - case 'yearly': - return RepeatInterval.yearly; - default: - return RepeatInterval.daily; // Default to daily if not recognized - } - } -} diff --git a/lib/models/common/task_model.dart b/lib/models/common/task_model.dart new file mode 100644 index 0000000..362472d --- /dev/null +++ b/lib/models/common/task_model.dart @@ -0,0 +1,84 @@ +import 'package:Organiser/models/classes/do_day.dart'; +import 'package:Organiser/models/classes/do_time.dart'; +import 'package:Organiser/models/classes/repeat_interval.dart'; +import 'package:Organiser/models/classes/repeat_type.dart'; +import 'package:Organiser/models/common/media_model.dart'; +import 'package:Organiser/models/enums/task_enums.dart'; + +class Task { + String id; + String title; + String hashtags; + String description; + DoDay doDay; + DoTime doTime; + TaskPriority priority; + bool repeat; + RepeatInterval? repeatInterval; + RepeatType? repeatType; + List? attachments; + Map? subtasks; + + Task({ + required this.id, + required this.title, + required this.description, + required this.doDay, + required this.doTime, + required this.priority, + required this.hashtags, + required this.repeat, + required this.repeatInterval, + required this.repeatType, + this.attachments, + this.subtasks, + }); + + // Factory constructor to create a Task instance from a Firebase snapshot + factory Task.fromMap(Map data, String documentId) { + return Task( + id: documentId, + title: data['title'] ?? '', + description: data['description'] ?? '', + subtasks: (data['subtasks'] != null) + ? Map.from(data['subtasks']) + : null, + doDay: DoDay(tangibleValue: data['doDay']), + doTime: DoTime(tangibleValue: data['doTime']), + priority: (data['priority'] != null) + ? TaskPriority.values[data['priority']] + : TaskPriority.low, + hashtags: data['hashtags'] ?? '', + repeat: data['repeat'] ?? false, + repeatInterval: RepeatInterval( + type: data['repeatInterval']['type'], + every: data['repeatInterval']['every'], + ), + repeatType: RepeatType( + type: data['repeatType']['type'], + value: data['repeatType']['value'], + ), + attachments: (data['attachments'] != null) + ? List.from( + data['attachments'].map((item) => MediaType.fromJson(item))) + : null, + ); + } + + // Method to convert Task instance to a map for Firebase + Map toMap() { + return { + 'title': title, + 'description': description, + 'subtasks': subtasks, + 'doDay': doDay.tangibleValue, + 'doTime': doTime.tangibleValue, + 'priority': priority.index, + 'hashtags': hashtags, + 'repeat': repeat, + 'repeatInterval': repeatInterval?.toMap(), + 'repeatType': repeatType?.toMap(), + 'attachments': attachments?.map((media) => media.toJson()).toList(), + }; + } +} diff --git a/lib/models/common/user_settings_model.dart b/lib/models/common/user_settings_model.dart new file mode 100644 index 0000000..1fa222d --- /dev/null +++ b/lib/models/common/user_settings_model.dart @@ -0,0 +1,29 @@ +class UserSettings { + bool darkMode; + int defaultPriority; + bool notificationsEnabled; + + UserSettings({ + required this.darkMode, + required this.defaultPriority, + required this.notificationsEnabled, + }); + + // Factory constructor to create a UserSettings instance from a map + factory UserSettings.fromMap(Map map) { + return UserSettings( + darkMode: map['darkMode'] ?? false, + defaultPriority: map['defaultPriority'] ?? 0, + notificationsEnabled: map['notificationsEnabled'] ?? true, + ); + } + + // Method to convert UserSettings instance to a map + Map toMap() { + return { + 'darkMode': darkMode, + 'defaultPriority': defaultPriority, + 'notificationsEnabled': notificationsEnabled, + }; + } +} diff --git a/lib/models/community.dart b/lib/models/community.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/models/community_model.dart b/lib/models/community_model.dart new file mode 100644 index 0000000..2eb861a --- /dev/null +++ b/lib/models/community_model.dart @@ -0,0 +1,40 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; + +class Community { + String id; + String name; + String description; + String creatorId; + String imageUrl; + Timestamp createdAt; + + Community({ + required this.id, + required this.name, + required this.description, + required this.creatorId, + required this.imageUrl, + required this.createdAt, + }); + + factory Community.fromMap(Map data, String documentId) { + return Community( + id: documentId, + name: data['name'], + description: data['description'], + creatorId: data['creatorId'], + imageUrl: data['imageUrl'], + createdAt: data['createdAt'], + ); + } + + Map toMap() { + return { + 'name': name, + 'description': description, + 'creatorId': creatorId, + 'imageUrl': imageUrl, + 'createdAt': createdAt, + }; + } +} diff --git a/lib/models/enums/meal_enums.dart b/lib/models/enums/meal_enums.dart new file mode 100644 index 0000000..1ba56ce --- /dev/null +++ b/lib/models/enums/meal_enums.dart @@ -0,0 +1,8 @@ +enum MealType { + fastFood, + breakfast, + lunch, + supper, + snack, +} + diff --git a/lib/models/enums/task_enums.dart b/lib/models/enums/task_enums.dart new file mode 100644 index 0000000..c62b7e4 --- /dev/null +++ b/lib/models/enums/task_enums.dart @@ -0,0 +1,3 @@ +enum TaskStatus { todo, pending, inProgress, done, archived } + +enum TaskPriority { low, medium, high } diff --git a/lib/models/enums/time_enums.dart b/lib/models/enums/time_enums.dart new file mode 100644 index 0000000..5b4ed38 --- /dev/null +++ b/lib/models/enums/time_enums.dart @@ -0,0 +1,18 @@ + +enum RepeatIntervalEnum { daily, weekly, monthly, yearly } + +enum RepeatTypeEnum { repeatUntil, repeatCount, infinite } + +enum DoTimeEnum { morning, afternoon, evening, night, custom, none, midnight, noon } + +enum DoDayEnum { today, tomorrow, weekDay, custom, none } + +enum DayOfWeek { + monday, + tuesday, + wednesday, + thursday, + friday, + saturday, + sunday +} diff --git a/lib/models/group.dart b/lib/models/group.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/models/group_model.dart b/lib/models/group_model.dart new file mode 100644 index 0000000..b4ab9dc --- /dev/null +++ b/lib/models/group_model.dart @@ -0,0 +1,44 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; + +class Group { + String id; + String name; + String description; + String creatorId; + List members; + String imageUrl; + Timestamp createdAt; + + Group({ + required this.id, + required this.name, + required this.description, + required this.creatorId, + required this.members, + required this.imageUrl, + required this.createdAt, + }); + + factory Group.fromMap(Map data, String documentId) { + return Group( + id: documentId, + name: data['name'], + description: data['description'], + creatorId: data['creatorId'], + members: List.from(data['members']), + imageUrl: data['imageUrl'], + createdAt: data['createdAt'], + ); + } + + Map toMap() { + return { + 'name': name, + 'description': description, + 'creatorId': creatorId, + 'members': members, + 'imageUrl': imageUrl, + 'createdAt': createdAt, + }; + } +} diff --git a/lib/models/market_model.dart b/lib/models/market_model.dart new file mode 100644 index 0000000..8811a76 --- /dev/null +++ b/lib/models/market_model.dart @@ -0,0 +1,35 @@ +class Market { + String id; + String name; + String description; + String type; + String imageUrl; + + Market({ + required this.id, + required this.name, + required this.description, + required this.type, + required this.imageUrl, + }); + + factory Market.fromJson(Map json) { + return Market( + id: json['id'], + name: json['name'], + description: json['description'], + type: json['type'], + imageUrl: json['imageUrl'], + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'description': description, + 'type': type, + 'imageUrl': imageUrl, + }; + } +} diff --git a/lib/models/user.dart b/lib/models/user_model.dart similarity index 100% rename from lib/models/user.dart rename to lib/models/user_model.dart diff --git a/lib/views/pages/auth/account.dart b/lib/views/pages/auth/account.dart index 4a782f2..a03852f 100644 --- a/lib/views/pages/auth/account.dart +++ b/lib/views/pages/auth/account.dart @@ -1,4 +1,4 @@ -import 'package:Organiser/models/user.dart'; +import 'package:Organiser/models/user_model.dart'; import 'package:Organiser/views/services/user_provider.dart'; import 'package:Organiser/views/widgets/common/custom_appbar.dart'; import 'package:Organiser/views/widgets/styled/account_page/user_actions.dart'; diff --git a/lib/views/pages/auth/add_user_info.dart b/lib/views/pages/auth/add_user_info.dart index a9c9a49..176d95e 100644 --- a/lib/views/pages/auth/add_user_info.dart +++ b/lib/views/pages/auth/add_user_info.dart @@ -1,6 +1,6 @@ import 'dart:io'; import 'package:Organiser/controllers/file_controller.dart'; -import 'package:Organiser/models/user.dart'; +import 'package:Organiser/models/user_model.dart'; import 'package:Organiser/views/pages/landing_page.dart'; import 'package:Organiser/views/services/user_provider.dart'; import 'package:Organiser/views/widgets/common/auth/auth_buttons.dart'; diff --git a/lib/views/pages/forms/add_event.dart b/lib/views/pages/forms/add_event.dart index bca74f3..18a566a 100644 --- a/lib/views/pages/forms/add_event.dart +++ b/lib/views/pages/forms/add_event.dart @@ -1,18 +1,5 @@ -import 'package:Organiser/models/common/event.dart'; -import 'package:Organiser/models/common/meal.dart'; -import 'package:Organiser/views/widgets/styled/input_adder/repeat.dart'; -import 'package:Organiser/views/widgets/styled/input_adder/timezone.dart'; import 'package:flutter/material.dart'; -import 'package:Organiser/controllers/common/event_controller.dart'; -import 'package:Organiser/views/widgets/styled/input_adder/title.dart'; -import 'package:Organiser/views/widgets/styled/input_adder/note.dart'; -import 'package:Organiser/views/widgets/styled/input_adder/cartegory.dart'; -import 'package:Organiser/views/widgets/styled/input_adder/tag.dart'; -import 'package:Organiser/views/widgets/styled/input_adder/image.dart'; -import 'package:Organiser/views/widgets/styled/input_adder/date_duration.dart'; -import 'package:Organiser/views/widgets/styled/input_adder/location.dart'; -import 'package:Organiser/views/widgets/styled/input_adder/ticket.dart'; -import 'package:Organiser/views/widgets/styled/input_adder/optionsAppBar.dart'; +import 'package:Organiser/views/widgets/styled/form_fields/options_appbar.dart'; class CreateEventPage extends StatefulWidget { @override @@ -20,82 +7,14 @@ class CreateEventPage extends StatefulWidget { } class _CreateEventPageState extends State { - //create a the required controllers for event model - final TextEditingController _titleController = TextEditingController(); - final TextEditingController _priorityController = TextEditingController(); - final TextEditingController _notesController = TextEditingController(); - final TextEditingController _cartegoryController = TextEditingController(); - final List _tagsController = []; - final String _photoUrlController = ''; - final Map _dateAndTimeController = {}; - final bool _isRepetingController = true; - final Map _repetitionController = {}; - final Map _locationController = {}; - final TextEditingController _ticketsController = TextEditingController(); - final TextEditingController _ticketCostController = TextEditingController(); - final TextEditingController _timezoneConroller = TextEditingController(); final GlobalKey _formKey = GlobalKey(); @override Widget build(BuildContext context) { return Scaffold( - body: SafeArea( - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Form( - key: _formKey, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - TitleAdder( - titleController: _titleController, - priorityController: _priorityController), - SizedBox(height: 16.0), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - NotesAdder( - notesController: _notesController, - ), - CartegoryAdder( - cartegoryController: _cartegoryController, - ), - TagsAdder( - selectedTags: _tagsController, - ), - ImageAdder( - imageUrlController: _photoUrlController, - ), - ], - ), - SizedBox(height: 16.0), - DateAndTimeAdder( - dateAndTimeController: _dateAndTimeController, - ), - SizedBox(height: 16.0), - RepeatAdderWidget( - repeatOnController: _isRepetingController, - repeatController: _repetitionController, - ), - SizedBox(height: 16.0), - LocationAdder( - locationController: _locationController, - ), - SizedBox(height: 16.0), - TicketsAdder( - ticketsController: _ticketsController, - costPerTicketController: _ticketCostController, - ), - SizedBox(height: 16.0), - TimezoneAdder( - timezoneConroller: _timezoneConroller, - ) - ], - ), - ), - ), - ), + backgroundColor: Colors.transparent, + body: Center( + child: Text("create"), ), bottomNavigationBar: OptionsAppBar( cancelTitle: 'CANCEL', @@ -112,20 +31,6 @@ class _CreateEventPageState extends State { } void createEvent() { - Event newEvent = Event( - title: _titleController.text, - priority: _priorityController.text, - notes: _notesController.text, - category: _cartegoryController.text, - tags: _tagsController, - photoURL: _photoUrlController, - dateAndTime: [_dateAndTimeController], - isRepeating: _isRepetingController, - repetition: [_repetitionController], - location: [_locationController], - ticketCost: _ticketCostController.text as double, - numberOfTickets: _ticketsController.text as int, - timezone: _timezoneConroller.text); Navigator.pop(context); } diff --git a/lib/views/pages/forms/add_goal.dart b/lib/views/pages/forms/add_goal.dart index e69de29..07342f3 100644 --- a/lib/views/pages/forms/add_goal.dart +++ b/lib/views/pages/forms/add_goal.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:Organiser/views/widgets/styled/form_fields/options_appbar.dart'; + +class CreateGoalPage extends StatefulWidget { + @override + _CreateGoalPageState createState() => _CreateGoalPageState(); +} + +class _CreateGoalPageState extends State { + final GlobalKey _formKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.transparent, + body:Center( + child: Text("create"), + ), + bottomNavigationBar: OptionsAppBar( + cancelTitle: 'CANCEL', + formKey: _formKey, + AcceptTitle: 'SAVE', + onCancelClicked: () { + createDraft(); + }, + onAcceptClicked: () { + createGoal(); + }, + ), + ); + } + + void createGoal() { + Navigator.pop(context); + } + + void createDraft() { + Navigator.pop(context); + } +} diff --git a/lib/views/pages/forms/add_meal.dart b/lib/views/pages/forms/add_meal.dart index e69de29..9e83ac6 100644 --- a/lib/views/pages/forms/add_meal.dart +++ b/lib/views/pages/forms/add_meal.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:Organiser/views/widgets/styled/form_fields/options_appbar.dart'; + +class CreateMealPage extends StatefulWidget { + @override + _CreateMealPageState createState() => _CreateMealPageState(); +} + +class _CreateMealPageState extends State { + final GlobalKey _formKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.transparent, + body:Center( + child: Text("create"), + ), + bottomNavigationBar: OptionsAppBar( + cancelTitle: 'CANCEL', + formKey: _formKey, + AcceptTitle: 'SAVE', + onCancelClicked: () { + createDraft(); + }, + onAcceptClicked: () { + createMeal(); + }, + ), + ); + } + + void createMeal() { + Navigator.pop(context); + } + + void createDraft() { + Navigator.pop(context); + } +} diff --git a/lib/views/pages/forms/add_schedule.dart b/lib/views/pages/forms/add_schedule.dart index e69de29..d22454f 100644 --- a/lib/views/pages/forms/add_schedule.dart +++ b/lib/views/pages/forms/add_schedule.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:Organiser/views/widgets/styled/form_fields/options_appbar.dart'; + +class CreateSchedulePage extends StatefulWidget { + @override + _CreateSchedulePageState createState() => _CreateSchedulePageState(); +} + +class _CreateSchedulePageState extends State { + final GlobalKey _formKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.transparent, + body: Center( + child: Text("create"), + ), + bottomNavigationBar: OptionsAppBar( + cancelTitle: 'CANCEL', + formKey: _formKey, + AcceptTitle: 'SAVE', + onCancelClicked: () { + createDraft(); + }, + onAcceptClicked: () { + createSchedule(); + }, + ), + ); + } + + void createSchedule() { + // ignore: unused_local_variable + + Navigator.pop(context); + } + + void createDraft() { + Navigator.pop(context); + } +} diff --git a/lib/views/pages/forms/add_task.dart b/lib/views/pages/forms/add_task.dart index 476a454..8824be5 100644 --- a/lib/views/pages/forms/add_task.dart +++ b/lib/views/pages/forms/add_task.dart @@ -1,52 +1,257 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:Organiser/models/enums/task_enums.dart'; +import 'package:Organiser/models/classes/do_day.dart'; +import 'package:Organiser/models/classes/do_time.dart'; +import 'package:Organiser/models/classes/repeat_interval.dart'; +import 'package:Organiser/models/classes/repeat_type.dart'; +import 'package:Organiser/models/common/media_model.dart'; +import 'package:Organiser/models/common/task_model.dart'; +import 'package:Organiser/models/enums/time_enums.dart'; +import 'package:Organiser/views/services/common/task_provider.dart'; +import 'package:Organiser/views/services/user_provider.dart'; +import 'package:Organiser/views/widgets/styled/form_fields/files_upload.dart'; +import 'package:Organiser/views/widgets/styled/form_fields/sub_tasks_field.dart'; +import 'package:Organiser/views/widgets/styled/form_fields/text_field.dart'; +import 'package:Organiser/views/widgets/styled/form_fields/dropdown.dart'; +import 'package:Organiser/views/widgets/styled/form_fields/options_appbar.dart'; +import 'package:Organiser/views/widgets/styled/form_fields/segmented_control.dart'; + class CreateTaskPage extends StatefulWidget { @override _CreateTaskPageState createState() => _CreateTaskPageState(); } class _CreateTaskPageState extends State { - final TextEditingController _titleController = TextEditingController(); - final TextEditingController _descriptionController = TextEditingController(); + final GlobalKey _formKey = GlobalKey(); + + // TASK MODEL PROPERTIES + final _titleController = TextEditingController(); + final _descriptionController = TextEditingController(); + final _hashtagsController = TextEditingController(); + final _attachmentController = TextEditingController(); + List _attachments = []; + DoDayEnum _doDayEDoDayEnum = DoDayEnum.none; + DoTimeEnum _doTimeEnumDoTimeEnum = DoTimeEnum.none; + TaskPriority _priority = TaskPriority.low; + bool _repeat = false; + RepeatIntervalEnum _repeatInterval = RepeatIntervalEnum.daily; + Map? _subtasks = {}; @override Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - TextField( - controller: _titleController, - decoration: InputDecoration( + final userProvider = Provider.of(context); + + final taskProvider = TaskProvider.create( + controllerSource: 'users', controllerUserId: userProvider.user!.id); + + return Scaffold( + backgroundColor: Colors.transparent, + body: Form( + key: _formKey, + child: ListView( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 0), + children: [ + FormTextField( labelText: 'Title', + controller: _titleController, + placeholder: 'Enter task title', + required: true, + suffix: Icon(Icons.title), ), - ), - SizedBox(height: 16.0), - TextField( - controller: _descriptionController, - decoration: InputDecoration( + SizedBox(height: 16), + FormTextField( labelText: 'Description', + controller: _descriptionController, + placeholder: 'Enter task description', + required: true, + keyboardType: TextInputType.multiline, + suffix: Icon(Icons.description), + ), + SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: FormDropDown( + labelText: 'Do Day', + value: _doDayEDoDayEnum, + items: DoDayEnum.values, + onChanged: (value) { + setState(() { + _doDayEDoDayEnum = value!; + }); + }, + required: true, + customValueOptions: [ + DoDayEnum.custom, + DoDayEnum.weekDay, + ], + onCustomValueSelected: (BuildContext context) async { + // Implement custom value selection logic here + return null; + }, + ), + ), + SizedBox(width: 16), + Expanded( + child: FormDropDown( + labelText: 'Do Time', + value: _doTimeEnumDoTimeEnum, + items: DoTimeEnum.values, + onChanged: (value) { + setState(() { + _doTimeEnumDoTimeEnum = value!; + }); + }, + required: true, + customValueOptions: [ + DoTimeEnum.custom, + ], + onCustomValueSelected: (BuildContext context) async { + // Implement custom value selection logic here + final TimeOfDay? picked = await showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ); + return picked as DoTimeEnum; + }, + ), + ), + ], + ), + SizedBox(height: 16), + SegmentedControl( + segments: { + TaskPriority.low.index: Text('Low'), + TaskPriority.medium.index: Text('Medium'), + TaskPriority.high.index: Text('High'), + }, + currentValue: _priority.index, + onChanged: (value) { + setState(() { + _priority = TaskPriority.values[value]; + }); + }, + title: 'Priority', ), - maxLines: 3, - ), - SizedBox(height: 16.0), - ElevatedButton( - onPressed: () { - _saveTask(); - Navigator.pop(context); - }, - child: Text('Save'), - ), - ], + SizedBox(height: 16), + FileUploadDropZone( + title: 'Attachments', + controller: _attachmentController, + ), + SizedBox(height: 16), + FormTextField( + labelText: 'Hashtags', + controller: _hashtagsController, + placeholder: 'Enter hashtags separated by commas', + suffix: Icon(Icons.tag), + ), + SizedBox(height: 10), + SwitchListTile( + contentPadding: EdgeInsets.zero, + title: Text('Repeat', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Theme.of(context).primaryColor)), + value: _repeat, + onChanged: (value) { + setState(() { + _repeat = value; + }); + }, + ), + if (_repeat) ...[ + SegmentedControl( + segments: { + RepeatIntervalEnum.daily.index: Text('Daily'), + RepeatIntervalEnum.weekly.index: Text('Weekly'), + RepeatIntervalEnum.monthly.index: Text('Monthly'), + RepeatIntervalEnum.yearly.index: Text('Yearly'), + }, + currentValue: _repeatInterval.index, + onChanged: (value) { + setState(() { + _repeatInterval = RepeatIntervalEnum.values[value]; + }); + }, + title: 'Repeat Interval', + ), + ], + SizedBox(height: 10), + SubtaskWidget( + subtasks: _subtasks, + onChanged: (subtasks) { + setState(() { + _subtasks = subtasks; + }); + }, + ), + ], + ), + ), + bottomNavigationBar: OptionsAppBar( + cancelTitle: 'CANCEL', + formKey: _formKey, + AcceptTitle: 'SAVE', + onCancelClicked: () { + createDraft(); + }, + onAcceptClicked: () { + if (_formKey.currentState!.validate()) { + createTask(taskProvider); + } + }, ), ); } - void _saveTask() { - final String title = _titleController.text.trim(); - final String description = _descriptionController.text.trim(); + void createTask(TaskProvider taskProvider) async { + Task task = Task( + id: '', + title: _titleController.text, + description: _descriptionController.text, + doDay: _doDayEDoDayEnum == DoDayEnum.custom + ? DoDay(tangibleValue: DateTime.now()) + : DoDay.fromEnum(_doDayEDoDayEnum), + doTime: _doTimeEnumDoTimeEnum == DoTimeEnum.custom + ? DoTime(tangibleValue: TimeOfDay.now()) + : DoTime.fromEnum(_doTimeEnumDoTimeEnum), + priority: _priority, + hashtags: _hashtagsController.text, + repeat: _repeat, + repeatInterval: RepeatInterval(type: _repeatInterval, every: 1), + repeatType: RepeatType(type: RepeatTypeEnum.infinite), + attachments: _attachments, + subtasks: _subtasks, + ); + + // Create the task using TaskProvider + await taskProvider.createTask(task, context); + + // Navigate back or perform further actions + } + + void createDraft() { + // Create draft logic here + Navigator.pop(context); + } - // Implement your logic to save the task here - print('Title: $title, Description: $description'); + Widget _buildLoadingWidget() { + return Center( + child: CircularProgressIndicator(), + ); + } + + Widget _buildErrorWidget(String error) { + return Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + error, + style: TextStyle(color: Colors.red), + ), + ), + ); } } diff --git a/lib/views/pages/home/home_page.dart b/lib/views/pages/home/home_page.dart index 8602bef..d2277f1 100644 --- a/lib/views/pages/home/home_page.dart +++ b/lib/views/pages/home/home_page.dart @@ -43,7 +43,7 @@ class _HomePageState extends State { }); }, ), - floatingActionButton: CustomFAB(), + floatingActionButton: CustomFAB(), floatingActionButtonLocation: FloatingActionButtonLocation.miniEndFloat, ); } diff --git a/lib/views/pages/home/screens/dashboard.dart b/lib/views/pages/home/screens/dashboard.dart index b0d5dfd..17ee422 100644 --- a/lib/views/pages/home/screens/dashboard.dart +++ b/lib/views/pages/home/screens/dashboard.dart @@ -18,233 +18,7 @@ class _DashboardState extends State { child: SafeArea( child: Column( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - margin: const EdgeInsets.all(5), - padding: const EdgeInsets.all(10), - height: 500, - width: double.infinity, - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - border: Border.all( - color: Theme.of(context) - .colorScheme - .primary - .withOpacity(0.1)), - borderRadius: BorderRadius.circular(15), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Row( - children: [ - Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Activity Overview', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.bold, - ), - ), - Row( - children: [ - Text( - 'Tasks', - style: TextStyle( - fontSize: 12.0, - color: Colors.grey, - ), - ), - SizedBox( - width: 5, - ), - Icon( - Icons.arrow_forward_ios, - size: 10, - ), - SizedBox( - width: 5, - ), - Text( - "This Week", - style: TextStyle( - fontSize: 12.0, - color: Colors.grey, - ), - ), - ], - ), - ], - ), - ], - ), - Divider( - color: Colors.grey.withOpacity(0.5), - ), - ], - ), - ), - Container( - margin: const EdgeInsets.all(5), - padding: const EdgeInsets.all(5), - height: 230, - width: double.infinity, - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - border: Border.all( - color: Theme.of(context) - .colorScheme - .primary - .withOpacity(0.1)), - borderRadius: BorderRadius.circular(15), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Row( - children: [ - Text( - 'Goals Progress', - style: TextStyle( - fontSize: 15.0, - fontWeight: FontWeight.bold, - ), - ), - // Add a spacer - Spacer(), - IconButton( - onPressed: () => {}, - icon: Icon( - Icons.arrow_forward_ios, - size: 15, - )) - ], - ), - Divider( - height: 1, - color: Colors.grey.withOpacity(0.5), - ), - Expanded( - child: Column( - children: [ - SizedBox(height: 10), - Row( - children: [ - Text("Buy a new car", - style: TextStyle( - color: Colors.grey, - )), - Spacer(), - Text("50%", - style: TextStyle( - color: Colors.grey, - )), - ], - ), - LinearProgressIndicator( - minHeight: 10, - borderRadius: BorderRadius.circular(15), - value: 0.9, - backgroundColor: Colors.grey.withOpacity(0.5), - valueColor: - AlwaysStoppedAnimation(Colors.green), - ), - SizedBox(height: 10), - Row( - children: [ - Text("Learn Data Science", - style: TextStyle( - color: Colors.grey, - )), - Spacer(), - Text("70%", - style: TextStyle( - color: Colors.grey, - )), - ], - ), - LinearProgressIndicator( - minHeight: 10, - borderRadius: BorderRadius.circular(15), - value: 0.7, - backgroundColor: Colors.grey.withOpacity(0.5), - valueColor: - AlwaysStoppedAnimation(Colors.amber), - ), - SizedBox(height: 10), - Row( - children: [ - Text("Build Organiser App", - style: TextStyle( - color: Colors.grey, - )), - Spacer(), - Text("30%", - style: TextStyle( - color: Colors.grey, - )), - ], - ), - LinearProgressIndicator( - minHeight: 10, - borderRadius: BorderRadius.circular(15), - value: 0.3, - backgroundColor: Colors.grey.withOpacity(0.5), - valueColor: AlwaysStoppedAnimation( - Colors.redAccent - ), - ), - ], - ), - ), - Text("You're on track to achieve your goals", - style: TextStyle( - fontSize: 12.0, - )), - ], - ), - ), - Container( - margin: const EdgeInsets.all(5), - padding: const EdgeInsets.all(5), - height: 700, - width: double.infinity, - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - border: Border.all( - color: Theme.of(context) - .colorScheme - .primary - .withOpacity(0.1)), - borderRadius: BorderRadius.circular(15), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Welcome to Organiser', - style: TextStyle( - fontSize: 20.0, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 10), - Text( - 'Organise your life with ease', - style: TextStyle( - fontSize: 12.0, - color: Colors.grey, - ), - ), - const SizedBox(height: 20), - ], - ), - ) - ], + children: [], ), ), ), diff --git a/lib/views/pages/home/screens/food.dart b/lib/views/pages/home/screens/food.dart index 8f97520..8198d49 100644 --- a/lib/views/pages/home/screens/food.dart +++ b/lib/views/pages/home/screens/food.dart @@ -1,7 +1,7 @@ import 'package:Organiser/views/widgets/common/tabs_appbar.dart'; import 'package:flutter/material.dart'; -class Food extends StatefulWidget { +class Food extends StatefulWidget { const Food({Key? key}) : super(key: key); @override @@ -16,65 +16,37 @@ class _FoodState extends State { child: Scaffold( backgroundColor: Colors.transparent, extendBodyBehindAppBar: true, - appBar: TabsAppBar(tabs: [ - Tab(child: Text("meals"),), + appBar: TabsAppBar(title: "Food", actions: [ + IconButton(onPressed: () {}, icon: Icon(Icons.add)), + IconButton(onPressed: () {}, icon: Icon(Icons.calendar_month)), + ], tabs: [ Tab( - child: Text("market Place"), + child: Text("Meals"), + ), + Tab( + child: Text("Market Place"), ) - ]), body: TabBarView( children: [ - _buildMealsPage(), - _buildMarketplacePage(), + _buildMealsView(), + _buildMarketView(), ], ), ), ); } - Widget _buildMealsPage() { - return SingleChildScrollView( - child: SafeArea( - child: Column( - children: [ - Card( - child: ListTile( - title: Text('Meal 1'), - subtitle: Text('Description for Meal 1'), - // Customize the card as needed for your meal representation - ), - ), - Card( - child: ListTile( - title: Text('Meal 2'), - subtitle: Text('Description for Meal 2'), - // Customize the card as needed for your meal representation - ), - ), - // Add more cards for other meals - ], - ), - ), + Widget _buildMealsView() { + return Center( + child: Text('Meals View'), ); } - Widget _buildMarketplacePage() { - List restaurants = [ - 'Restaurant A', - 'Restaurant B', - 'Restaurant C', - // Add more restaurants as needed - ]; - - return ListView.builder( - itemCount: restaurants.length, - itemBuilder: (context, index) { - return ListTile( - title: Text(restaurants[index]), - // Customize the ListTile as needed for your restaurant representation - ); - }, + Widget _buildMarketView() { + // You can customize this view for displaying events + return Center( + child: Text('Market View'), ); } } diff --git a/lib/views/pages/home/screens/schedules.dart b/lib/views/pages/home/screens/schedules.dart index 956be18..98b3066 100644 --- a/lib/views/pages/home/screens/schedules.dart +++ b/lib/views/pages/home/screens/schedules.dart @@ -1,4 +1,4 @@ -import 'package:Organiser/views/widgets/common/tabs_appbar.dart'; +import 'package:Organiser/views/widgets/common/custom_appbar.dart'; import 'package:flutter/material.dart'; // import 'package:syncfusion_flutter_calendar/calendar.dart'; @@ -13,25 +13,18 @@ class _SchedulesState extends State with SingleTickerProviderStateMixin { @override Widget build(BuildContext context) { - return DefaultTabController( - length: 2, - child: Scaffold( - backgroundColor: Colors.transparent, - appBar: TabsAppBar( - tabs: [ - Tab(text: 'Schedules'), - Tab( - text: 'Events', - ), - ], - ), - body: TabBarView( - children: [ - _buildSchedulesView(), - _buildEventsView(), - ], - ), + return Scaffold( + backgroundColor: Colors.transparent, + appBar: CustomAppBar( + leadingWidth: 0, + leading: Text(""), + centerTitle: false, + title: Text("Calendar"), + actions: [ + IconButton(onPressed: () {}, icon: Icon(Icons.add)), + ], ), + body: _buildSchedulesView(), ); } @@ -40,11 +33,4 @@ class _SchedulesState extends State child: Text('Schedules View'), ); } - - Widget _buildEventsView() { - // You can customize this view for displaying events - return Center( - child: Text('Events View'), - ); - } } diff --git a/lib/views/pages/home/screens/socials.dart b/lib/views/pages/home/screens/socials.dart index d603ca9..f50177b 100644 --- a/lib/views/pages/home/screens/socials.dart +++ b/lib/views/pages/home/screens/socials.dart @@ -1,4 +1,4 @@ -import 'package:Organiser/views/widgets/common/tabs_appbar.dart'; +import 'package:Organiser/views/widgets/common/custom_appbar.dart'; import 'package:flutter/material.dart'; class Socials extends StatefulWidget { @@ -11,139 +11,17 @@ class Socials extends StatefulWidget { class _SocialsState extends State { @override Widget build(BuildContext context) { - return DefaultTabController( - length: 2, - child: Scaffold( - extendBodyBehindAppBar: true, - backgroundColor: Colors.transparent, - appBar: TabsAppBar( - tabs: [ - Tab( - text: 'Groups', - ), - Tab( - text: 'Communities', - ), - ], - ), - body: TabBarView( - children: [ - Screen1(), - Screen2(), - ], - ), - ), - ); - } -} - -class Screen1 extends StatelessWidget { - @override - Widget build(BuildContext context) { - return ListView.builder( - itemCount: 20, // Replace with your actual list length - itemBuilder: (context, index) { - return ChatListItem( - groupName: 'Group $index', - iconLabels: ['Events', 'Tasks', 'Goals', 'Schedules'], - iconNumbers: [3, 5, 7, 2], // Replace with your actual numbers - ); - }); - } -} - -class Screen2 extends StatelessWidget { - @override - Widget build(BuildContext context) { - return ListView.builder( - itemCount: 15, // Replace with your actual list length - itemBuilder: (context, index) { - return CommunityListItem( - communityName: 'Community $index', - eventsCount: 8, // Replace with your actual numbers - followersCount: 120, // Replace with your actual numbers - ); - }, - ); - } -} - -class ChatListItem extends StatelessWidget { - final String groupName; - final List iconLabels; - final List iconNumbers; - - const ChatListItem({ - required this.groupName, - required this.iconLabels, - required this.iconNumbers, - }); - - @override - Widget build(BuildContext context) { - return ListTile( - leading: CircleAvatar( - // Replace with your group image or initials logic - child: Text(groupName[0]), - ), - title: Text(groupName), - subtitle: Row( - children: List.generate( - iconLabels.length, - (index) => Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Column( - children: [ - Icon(Icons.assignment), - Text(iconLabels[index]), - Text( - '${iconNumbers[index]}', - style: TextStyle(fontWeight: FontWeight.bold), - ), - ], - ), - ), - ), - ), - ); - } -} - -class CommunityListItem extends StatelessWidget { - final String communityName; - final int eventsCount; - final int followersCount; - - const CommunityListItem({ - required this.communityName, - required this.eventsCount, - required this.followersCount, - }); - - @override - Widget build(BuildContext context) { - return ListTile( - leading: CircleAvatar( - // Replace with your community image or initials logic - child: Text(communityName[0]), - ), - title: Text(communityName), - subtitle: Row( - children: [ - Icon(Icons.event), - Text('$eventsCount Events'), - SizedBox(width: 16.0), - Icon(Icons.people), - Text('$followersCount Followers'), + return Scaffold( + appBar: CustomAppBar( + leadingWidth: 0, + leading: Text(""), + centerTitle: false, + title: Text("Colaborate"), + actions: [ + IconButton(onPressed: () {}, icon: Icon(Icons.add)), ], ), - trailing: ElevatedButton.icon( - onPressed: () { - // Handle follow button click - }, - icon: Icon(Icons.add), - label: Text('Follow'), - ), + body: Center(child: Text("WORK WITH OTHERS")), ); } } diff --git a/lib/views/pages/home/screens/tasks.dart b/lib/views/pages/home/screens/tasks.dart index bc6b890..fc9de3a 100644 --- a/lib/views/pages/home/screens/tasks.dart +++ b/lib/views/pages/home/screens/tasks.dart @@ -1,5 +1,5 @@ -import 'package:Organiser/views/widgets/common/custom_appbar.dart'; import 'package:flutter/material.dart'; +import 'package:Organiser/views/widgets/common/tabs_appbar.dart'; class Tasks extends StatefulWidget { const Tasks({Key? key}) : super(key: key); @@ -9,99 +9,58 @@ class Tasks extends StatefulWidget { } class _TasksState extends State { - List tasks = [ - 'Task 1', - 'Task 2', - 'Task 3', - 'Task 4', - 'Task 5', - 'Task 6', - 'Task 7', - 'Task 8', - ]; - - List filters = ['All', 'Pending', 'Completed']; - String selectedFilter = 'All'; - @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.transparent, - appBar: CustomAppBar( - leading: Icon(Icons.task), - centerTitle: false, - title: Text('Tasks'), - actions: [ - _buildFilterChips(), - ], - ), - body: _buildTaskList(), - ); - } - - Widget _buildFilterChips() { - return Wrap( - spacing: 8.0, - children: filters.map((filter) { - return FilterChip( - label: Text(filter), - - side: BorderSide( - color: Theme.of(context) - .primaryColor - .withOpacity(0.5), // Use theme primary color for border - width: 0.5, // Adjust border width as needed + return DefaultTabController( + length: 3, + child: Scaffold( + backgroundColor: Colors.transparent, + appBar: TabsAppBar( + title: "Workspace", + tabs: [ + Tab( + text: 'Tasks', + ), + Tab( + text: 'Goals', + ), + Tab( + text: 'Events', + ), + ], + actions: [ + IconButton(onPressed: () {}, icon: Icon(Icons.add)), + IconButton(onPressed: () {}, icon: Icon(Icons.calendar_month)), + ], ), - - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(30.0), // Adjust border radius as needed - side: BorderSide( - color: Theme.of(context) - .primaryColor, // Use theme primary color for border - width: 1.0, // Adjust border width as needed - ), + body: TabBarView( + children: [ + _buildTasksView(), + _buildGoalsView(), + _buildEventsView() + ], ), - padding: EdgeInsets.symmetric( - horizontal: 1, vertical: 0.0), // Adjust padding as needed - color: MaterialStateProperty.resolveWith((states) => Theme.of(context) - .scaffoldBackgroundColor), // Use theme scaffoldBackgroundColor for chip background - checkmarkColor: Theme.of(context) - .primaryColor, // Use theme primary color for checkmark - labelStyle: TextStyle( - fontSize: 12.0, - fontWeight: FontWeight.w300, - color: Theme.of(context).primaryColor), - selected: selectedFilter == filter, - onSelected: (isSelected) { - setState(() { - selectedFilter = isSelected ? filter : 'All'; - }); - }, - ); - }).toList(), - ); + // _buildTaskList(), + )); } - Widget _buildTaskList() { - List filteredTasks = tasks; + Widget _buildTasksView() { + return Center( + child: Text('Tasks View'), + ); + } - // Apply filtering based on the selected filter - if (selectedFilter != 'All') { - filteredTasks = tasks.where((task) { - // You can customize this condition based on your task status - return task.contains(selectedFilter); - }).toList(); - } + Widget _buildGoalsView() { + // You can customize this view for displaying events + return Center( + child: Text('Goals View'), + ); + } - return ListView.builder( - itemCount: filteredTasks.length, - itemBuilder: (context, index) { - return ListTile( - title: Text(filteredTasks[index]), - // Customize the ListTile as needed for your task representation - ); - }, + Widget _buildEventsView() { + // You can customize this view for displaying events + return Center( + child: Text('Events View'), ); } } diff --git a/lib/views/pages/landing_page.dart b/lib/views/pages/landing_page.dart index 561de0f..188f5bd 100644 --- a/lib/views/pages/landing_page.dart +++ b/lib/views/pages/landing_page.dart @@ -1,4 +1,4 @@ -import 'package:Organiser/models/user.dart'; +import 'package:Organiser/models/user_model.dart'; import 'package:Organiser/views/pages/auth/add_user_info.dart'; import 'package:Organiser/views/pages/splash.dart'; import 'package:flutter/material.dart'; @@ -18,7 +18,7 @@ class LandingPage extends StatelessWidget { return Scaffold( body: Stack( children: [ - PageDecoration(), + // PageDecoration(), StreamBuilder( stream: FirebaseAuth.instance.authStateChanges(), builder: (context, snapshot) { diff --git a/lib/views/pages/onboarding_page.dart b/lib/views/pages/onboarding_page.dart index 05ec339..e83e712 100644 --- a/lib/views/pages/onboarding_page.dart +++ b/lib/views/pages/onboarding_page.dart @@ -152,14 +152,14 @@ class AuthPageDecoration extends StatelessWidget { Container( width: double.infinity, height: double.infinity, - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage( - 'assets/images/bg_decorate.webp', - ), - fit: BoxFit.cover, - ), - ), + // decoration: BoxDecoration( + // image: DecorationImage( + // image: AssetImage( + // 'assets/images/bg_decorate.webp', + // ), + // fit: BoxFit.cover, + // ), + // ), ), BackdropFilter( filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), diff --git a/lib/views/services/common/task_provider.dart b/lib/views/services/common/task_provider.dart new file mode 100644 index 0000000..4418037 --- /dev/null +++ b/lib/views/services/common/task_provider.dart @@ -0,0 +1,127 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:Organiser/controllers/common/task_controller.dart'; +import 'package:Organiser/models/common/task_model.dart'; +import 'package:Organiser/views/widgets/common/snack_bar.dart'; + +class TaskProvider with ChangeNotifier { + final TaskController _taskController; + final StreamController> _taskStreamController = + StreamController>.broadcast(); + List _tasks = []; + bool _isLoading = false; + String? _error; + + TaskProvider(this._taskController); + + List get tasks => _tasks; + Stream> get taskStream => _taskStreamController.stream; + bool get isLoading => _isLoading; + String? get error => _error; + + Future createTask(Task task, BuildContext context) async { + try { + _isLoading = true; + notifyListeners(); + + await _taskController.addTask(task); + _tasks.add(task); + _taskStreamController.add(_tasks); + + _showSuccessSnackbar(context, 'Task created successfully.'); + } catch (e) { + _error = 'Failed to create task: $e'; + _showErrorSnackbar(context, _error!); + } finally { + _isLoading = false; + notifyListeners(); + } + } + + Future getTasks(BuildContext context) async { + try { + _isLoading = true; + notifyListeners(); + + final tasks = await _taskController.getAllTasks(); + _tasks = tasks as List; + _taskStreamController.add(_tasks); + } catch (e) { + _error = 'Failed to fetch tasks: $e'; + _showErrorSnackbar(context, _error!); + } finally { + _isLoading = false; + notifyListeners(); + } + } + + Future updateTask(Task task, BuildContext context) async { + try { + _isLoading = true; + notifyListeners(); + + await _taskController.updateTask(task); + _tasks.removeWhere((element) => element.id == task.id); + _tasks.add(task); + _taskStreamController.add(_tasks); + + _showSuccessSnackbar(context, 'Task updated successfully.'); + } catch (e) { + _error = 'Failed to update task: $e'; + _showErrorSnackbar(context, _error!); + } finally { + _isLoading = false; + notifyListeners(); + } + } + + Future deleteTask(String taskId, BuildContext context) async { + try { + _isLoading = true; + notifyListeners(); + + await _taskController.deleteTask(taskId); + _tasks.removeWhere((element) => element.id == taskId); + _taskStreamController.add(_tasks); + + _showSuccessSnackbar(context, 'Task deleted successfully.'); + } catch (e) { + _error = 'Failed to delete task: $e'; + _showErrorSnackbar(context, _error!); + } finally { + _isLoading = false; + notifyListeners(); + } + } + + void _showSuccessSnackbar(BuildContext context, String message) { + CustomSnackbar.show(context, 'success', message); + } + + void _showErrorSnackbar(BuildContext context, String errorMessage) { + CustomSnackbar.show(context, 'error', errorMessage); + } + + @override + void dispose() { + _taskStreamController.close(); + super.dispose(); + } + + /// Factory method to create TaskProvider instance based on source and userId + static TaskProvider create({ + required String controllerSource, + required String controllerUserId, + }) { + print( + 'TaskProvider.create: controllerSource: $controllerSource, controllerUserId: $controllerUserId'); + + // Example: Logic to determine which controller to use based on controllerSource + final TaskController taskController = TaskController( + controllerSource, + controllerUserId, + ); + + return TaskProvider(taskController); + } +} diff --git a/lib/views/services/user_provider.dart b/lib/views/services/user_provider.dart index beebddf..5beada6 100644 --- a/lib/views/services/user_provider.dart +++ b/lib/views/services/user_provider.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:Organiser/controllers/user_controller.dart'; -import 'package:Organiser/models/user.dart'; +import 'package:Organiser/models/user_model.dart'; class UserProvider with ChangeNotifier { final UserController _userController = UserController(); diff --git a/lib/views/widgets/common/action_button.dart b/lib/views/widgets/common/action_button.dart index ab9ed94..969e32f 100644 --- a/lib/views/widgets/common/action_button.dart +++ b/lib/views/widgets/common/action_button.dart @@ -1,10 +1,9 @@ -import 'package:Organiser/config/themes/light.dart'; -import 'package:Organiser/controllers/common/event_controller.dart'; +import 'package:flutter/material.dart'; import 'package:Organiser/views/pages/forms/add_event.dart'; +import 'package:Organiser/views/pages/forms/add_goal.dart'; +import 'package:Organiser/views/pages/forms/add_meal.dart'; +import 'package:Organiser/views/pages/forms/add_schedule.dart'; import 'package:Organiser/views/pages/forms/add_task.dart'; -import 'package:Organiser/views/services/theme_provider.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; class CustomFAB extends StatefulWidget { @override @@ -20,127 +19,187 @@ class _CustomFABState extends State void initState() { super.initState(); fabAnimation = AnimationController( - duration: const Duration(milliseconds: 500), + duration: const Duration(milliseconds: 300), vsync: this, ); } @override Widget build(BuildContext context) { - final themeProvider = Provider.of(context); - - return AnimatedBuilder( - animation: fabAnimation, - builder: (context, child) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (isMenuOpen) - buildMenuItem(Icons.check_circle, () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => CreateTaskPage()), - ); - setState(() { - isMenuOpen = !isMenuOpen; - }); - }, themeProvider), - if (isMenuOpen) - buildMenuItem(Icons.schedule, () { - setState(() { - isMenuOpen = !isMenuOpen; - }); - }, themeProvider), - if (isMenuOpen) - buildMenuItem(Icons.stars_rounded, () { - setState(() { - isMenuOpen = !isMenuOpen; - }); - }, themeProvider), - if (isMenuOpen) - buildMenuItem(Icons.event, () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => CreateEventPage()), - ); - - setState(() { - isMenuOpen = !isMenuOpen; - }); - }, themeProvider), - if (isMenuOpen) - buildMenuItem(Icons.restaurant, () { - setState(() { - isMenuOpen = !isMenuOpen; - }); - }, themeProvider), - Container( - width: 50, - height: 50, - margin: EdgeInsets.symmetric(vertical: 3), - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: themeProvider.themeData == lightMode - ? Theme.of(context).primaryColor - : Theme.of(context).primaryColor.withOpacity(0.8), - width: 2)), - child: FloatingActionButton( - backgroundColor: themeProvider.themeData == lightMode - ? Theme.of(context).primaryColor.withOpacity(0.7) - : Theme.of(context).primaryColor.withOpacity(0.5), - child: Icon( - isMenuOpen ? Icons.close : Icons.add, - size: 35, - color: Colors.white, + return FloatingActionButton( + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + isMenuOpen ? Icons.close : Icons.add, + size: 35, + color: Colors.white, + ), + onPressed: () { + setState(() { + isMenuOpen = !isMenuOpen; + }); + if (isMenuOpen) { + showModalBottomSheet( + barrierColor: Colors.black12, + backgroundColor: + Theme.of(context).scaffoldBackgroundColor.withOpacity(0.97), + context: context, + isScrollControlled: true, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(5), + topRight: Radius.circular(5), + ), + ), + builder: (BuildContext context) { + return Container( + height: 335, + child: Column( + children: [ + Center( + child: Container( + margin: EdgeInsets.symmetric(vertical: 15), + width: 150, + height: 3, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30), + color: Theme.of(context).primaryColor, + ), + ), + ), + SingleChildScrollView( + child: Container( + padding: EdgeInsets.symmetric(horizontal: 50), + height: 300, + child: Column( + children: [ + buildMenuItem(Icons.check_circle, "New Task", () { + Navigator.pop(context); + _showBottomSheet( + context, "New Task", CreateTaskPage()); + }), + buildMenuItem(Icons.stars_rounded, "Set a Goal", + () { + Navigator.pop(context); + _showBottomSheet( + context, "Set a Goal", CreateGoalPage()); + }), + buildMenuItem(Icons.event, "Event", () { + Navigator.pop(context); + _showBottomSheet( + context, "Event", CreateEventPage()); + }), + buildMenuItem(Icons.schedule, "Schedule", () { + Navigator.pop(context); + _showBottomSheet( + context, "Schedule", CreateSchedulePage()); + }), + buildMenuItem(Icons.restaurant, "Create Meal", () { + Navigator.pop(context); + _showBottomSheet( + context, "Create Meal", CreateMealPage()); + }), + ], + ), + ), + ), + ], ), - // mini: true, - elevation: 4.0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(30.0)), - onPressed: () { - setState(() { - isMenuOpen = !isMenuOpen; - }); - fabAnimation.status == AnimationStatus.completed - ? fabAnimation.reverse() - : fabAnimation.forward(); - }, + ); + }, + ); + setState(() { + isMenuOpen = false; + }); + } + }, + ); + } + + void _showBottomSheet(BuildContext context, String title, Widget page) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + elevation: 0, + barrierColor: Colors.black12, + useSafeArea: true, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(25), + topRight: Radius.circular(25), + ), + ), + builder: (BuildContext context) { + return Container( + padding: EdgeInsets.zero, + constraints: BoxConstraints(maxHeight: 900), + height: MediaQuery.of(context).size.height * 0.98, + decoration: BoxDecoration( + border: Border.all( + width: 1, + color: Theme.of(context).primaryColor.withOpacity(0.2)), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(25), + topRight: Radius.circular(25), ), ), - ], - ); + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Container( + width: double.infinity, + padding: EdgeInsets.only(top: 5, left: 10, right: 10, bottom: 0), + margin: EdgeInsets.all(0), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + IconButton( + color: + Theme.of(context).hintColor, + icon: Icon( + Icons.close, + size: 20, + weight: 1, + ), + padding: EdgeInsets.all(0), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ), + ), + Expanded(child: page), + ], + )); }, ); } - Widget buildMenuItem( - IconData icon, VoidCallback onPressed, var themeProvider) { - return Container( - width: 47, - height: 47, - margin: EdgeInsets.symmetric(vertical: 3), - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: themeProvider.themeData == lightMode - ? Theme.of(context).primaryColor - : Theme.of(context).primaryColor.withOpacity(0.5), - width: 0.6)), - child: FloatingActionButton( - backgroundColor: themeProvider.themeData == lightMode - ? Theme.of(context).primaryColor.withOpacity(0.8) - : Theme.of(context).primaryColor.withOpacity(0.5), - elevation: 4.0, - shape: - RoundedRectangleBorder(borderRadius: BorderRadius.circular(30.0)), - // mini: true, - onPressed: onPressed, - child: Icon( - icon, - color: Colors.white, - size: 35.0, + Widget buildMenuItem(IconData icon, String label, VoidCallback onPressed) { + return InkWell( + onTap: onPressed, + splashColor: Theme.of(context).primaryColor.withOpacity(0.3), + highlightColor: Theme.of(context).primaryColor.withOpacity(0.1), + child: Container( + width: double.infinity, + padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16), + child: Row( + children: [ + Icon(icon, size: 30, color: Theme.of(context).primaryColor), + SizedBox(width: 20), + Text(label, style: TextStyle(fontSize: 20)), + ], ), ), ); diff --git a/lib/views/widgets/common/app_bar.dart b/lib/views/widgets/common/app_bar.dart index 2783382..9a16e02 100644 --- a/lib/views/widgets/common/app_bar.dart +++ b/lib/views/widgets/common/app_bar.dart @@ -1,5 +1,7 @@ +import 'package:Organiser/config/themes/light.dart'; import 'package:Organiser/views/pages/auth/account.dart'; import 'package:Organiser/views/pages/messages/messages.dart'; +import 'package:Organiser/views/services/theme_provider.dart'; import 'package:Organiser/views/services/user_provider.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -80,12 +82,12 @@ class _MainAppBarState extends State { fontSize: 16.0, color: Theme.of(context).colorScheme.primary, fontWeight: FontWeight.w400)), - Text(" "), - Text(formattedTime, - style: TextStyle( - fontSize: 17.0, - fontWeight: FontWeight.bold, - color: Theme.of(context).colorScheme.primary)), + // Text(" "), + // Text(formattedTime, + // style: TextStyle( + // fontSize: 17.0, + // fontWeight: FontWeight.bold, + // color: Theme.of(context).colorScheme.primary)), ], ), leading: GestureDetector( @@ -99,29 +101,31 @@ class _MainAppBarState extends State { children: [ IconButton( padding: EdgeInsets.all(0), - iconSize: 35.0, + iconSize: 30.0, onPressed: () => { //open drawer Scaffold.of(context).openDrawer() }, icon: Icon(Icons.menu)), - // Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisAlignment: MainAxisAlignment.center, - // children: [ - // Text('$greeting,', style: TextStyle(fontSize: 13.0)), - // Text( - // '${user != null ? user.fname : "Guest"}', - // style: TextStyle( - // color: Colors.grey, - // ), - // ), - // ], - // ), ], ), ), actions: [ + // toggle theme button + IconButton( + style: ButtonStyle( + padding: MaterialStateProperty.all(EdgeInsets.all(0)), + ), + icon: Icon(Provider.of(context).themeData == lightMode + ? Icons.dark_mode + : Icons.light_mode), + onPressed: () { + // Toggle theme + Provider.of(context, listen: false) + .toggleTheme(context); + }, + ), + NotificationBadgeIconButton( icon: Icons.notifications_outlined, badgeCount: 5, // Set the badge count here @@ -132,7 +136,6 @@ class _MainAppBarState extends State { ); }, ), - GestureDetector( onTap: () { Navigator.push( @@ -141,7 +144,7 @@ class _MainAppBarState extends State { ); }, child: Container( - margin: EdgeInsets.all(0), + margin: EdgeInsets.only(right: 10.0), padding: EdgeInsets.all(0), decoration: BoxDecoration( shape: BoxShape.circle, @@ -162,37 +165,6 @@ class _MainAppBarState extends State { ), ), ), - // PopupMenuButton to switch between time formats - PopupMenuButton( - iconSize: 35, - onSelected: (value) { - setState(() { - _timeFormat = DateFormat(value); - }); - }, - itemBuilder: (context) => [ - PopupMenuItem( - value: 'HH:mm:ss', - child: Row( - children: [ - Icon(Icons.access_time), - SizedBox(width: 8), - Text('24 Hours'), - ], - ), - ), - PopupMenuItem( - value: 'h:mm:ss a', - child: Row( - children: [ - Icon(Icons.lock_clock), - SizedBox(width: 8), - Text('AM/PM'), - ], - ), - ), - ], - ), ], ); } diff --git a/lib/views/widgets/common/bottom_app_bar.dart b/lib/views/widgets/common/bottom_app_bar.dart index 4c12f86..ff26b79 100644 --- a/lib/views/widgets/common/bottom_app_bar.dart +++ b/lib/views/widgets/common/bottom_app_bar.dart @@ -9,17 +9,25 @@ class CustomBottomAppBar extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - margin: EdgeInsets.only(bottom: 5, left: 5, right: 5), + constraints: BoxConstraints(maxWidth: 600), + margin: EdgeInsets.only(bottom: 0, left: 0, right: 0), decoration: BoxDecoration( // border: Border.all( // // color: Theme.of(context).colorScheme.primary.withOpacity(0.7), // width: 0.5, // ), - borderRadius: BorderRadius.circular(15), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), + border: Border.all( + color: Theme.of(context).colorScheme.primary.withOpacity(0.3), + width: 0.05, + ), gradient: LinearGradient( colors: [ - Theme.of(context).scaffoldBackgroundColor.withOpacity(0.9), - Theme.of(context).scaffoldBackgroundColor.withOpacity(0.75), + Theme.of(context).scaffoldBackgroundColor, + Theme.of(context).scaffoldBackgroundColor, ], begin: Alignment.topCenter, end: Alignment.bottomCenter, @@ -28,7 +36,7 @@ class CustomBottomAppBar extends StatelessWidget { child: BottomAppBar( shape: CircularNotchedRectangle(), height: 60, - padding: EdgeInsets.symmetric(horizontal: 12.0), + padding: EdgeInsets.symmetric(horizontal: 20.0), color: Colors.transparent, elevation: 0, child: Row( @@ -106,7 +114,7 @@ class CustomBottomAppBarItem extends StatelessWidget { children: [ Icon( iconData, - size: 32, + size: 27, color: isSelected ? Theme.of(context).colorScheme.primary : null, ), diff --git a/lib/views/widgets/common/custom_appbar.dart b/lib/views/widgets/common/custom_appbar.dart index b2317dd..1d9a2be 100644 --- a/lib/views/widgets/common/custom_appbar.dart +++ b/lib/views/widgets/common/custom_appbar.dart @@ -9,19 +9,26 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { this.leading, this.leadingWidth, this.centerTitle, + this.bottom, }); @override Widget build(BuildContext context) { return AppBar( backgroundColor: - Theme.of(context).scaffoldBackgroundColor.withOpacity(0.8), + Theme.of(context).scaffoldBackgroundColor.withOpacity(0.95), scrolledUnderElevation: 0.0, bottom: PreferredSize( preferredSize: Size.fromHeight(0.0), - child: Container( - color: Theme.of(context).colorScheme.primary.withOpacity(0.5), - height: 0.3, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + if (bottom != null) bottom!, + Container( + color: Theme.of(context).colorScheme.primary.withOpacity(0.5), + height: 0.3, + ), + ], ), ), title: title, @@ -37,6 +44,7 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { final Widget? leading; final double? leadingWidth; final bool? centerTitle; + final PreferredSizeWidget? bottom; @override Size get preferredSize => Size.fromHeight(kToolbarHeight); diff --git a/lib/views/widgets/common/custom_dialog.dart b/lib/views/widgets/common/custom_dialog.dart new file mode 100644 index 0000000..34963e1 --- /dev/null +++ b/lib/views/widgets/common/custom_dialog.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; + +class CustomDialog extends StatelessWidget { + final Widget child; + final String button1Text; + final String button2Text; + final VoidCallback? onButton1Pressed; + final VoidCallback? onButton2Pressed; + + const CustomDialog({ + Key? key, + required this.child, + required this.button1Text, + required this.button2Text, + required this.onButton1Pressed, + required this.onButton2Pressed, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Dialog( + insetPadding: EdgeInsets.symmetric(horizontal: 0, vertical: 0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + elevation: 0, + backgroundColor: Colors.transparent, + child: _buildDialogContent(context), + ); + } + + Widget _buildDialogContent(BuildContext context) { + return Container( + margin: EdgeInsets.all(16), + constraints: BoxConstraints(maxWidth: 500), + width: MediaQuery.of(context).size.width, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Theme.of(context).scaffoldBackgroundColor.withOpacity(0.97), + borderRadius: BorderRadius.circular(16), + border: Border.all(color: Theme.of(context).primaryColor), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + child, + SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + TextButton( + onPressed: onButton1Pressed, + child: Text(button1Text), + ), + TextButton( + onPressed: onButton2Pressed, + child: Text(button2Text), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/views/widgets/common/drawer.dart b/lib/views/widgets/common/drawer.dart index 03ff22b..411676e 100644 --- a/lib/views/widgets/common/drawer.dart +++ b/lib/views/widgets/common/drawer.dart @@ -1,5 +1,5 @@ -import 'package:Organiser/config/themes/light.dart'; -import 'package:Organiser/views/pages/auth/account.dart'; +import 'dart:ui'; + import 'package:Organiser/views/pages/info/about.dart'; import 'package:Organiser/views/pages/info/tips.dart'; import 'package:Organiser/views/pages/settings/settings.dart'; @@ -8,7 +8,6 @@ import 'package:Organiser/views/widgets/dialogs/logout.dart'; import 'package:Organiser/views/widgets/dialogs/rate_app.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:Organiser/views/services/theme_provider.dart'; class CustomDrawer extends StatelessWidget { const CustomDrawer(); @@ -43,95 +42,94 @@ class CustomDrawer extends StatelessWidget { Theme.of(context).scaffoldBackgroundColor.withOpacity(0.9), clipBehavior: Clip.hardEdge, shape: Border.all( - width: 0.5, color: Theme.of(context).primaryColor.withOpacity(0.5)), + width: 0.5, color: Theme.of(context).primaryColor.withOpacity(0.2)), child: Container( + color: Theme.of(context).scaffoldBackgroundColor.withOpacity(0.9), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - GestureDetector( - onTap: () => { - Navigator.push(context, - MaterialPageRoute(builder: (context) => AccountPage())) - }, - child: Consumer( - builder: (context, userProvider, _) { - final user = userProvider.user; - return SafeArea( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Container( - width: 50, - height: 50, - decoration: BoxDecoration( - - shape: BoxShape.circle, - border: Border.all( - color: - Theme.of(context).colorScheme.primary, - width: 1.0, // Adjust the width as needed - ), - ), - child: CircleAvatar( - backgroundColor: Colors.transparent, - maxRadius: 10.0, - backgroundImage: user != null && - user.profilePhotoUrl != null - ? NetworkImage( - user.profilePhotoUrl ?? '') - : null, - child: user != null && - user.profilePhotoUrl == null - ? Icon(Icons.person) - : null, - ), + Consumer( + builder: (context, userProvider, _) { + final user = userProvider.user; + return Container( + width: double.infinity, + decoration: BoxDecoration( + // image: DecorationImage( + // image: NetworkImage('https://source.unsplash.com/random'), + // fit: BoxFit.cover, + // ), + color: Theme.of(context).colorScheme.primary, + ), + child: Container( + color: Theme.of(context) + .scaffoldBackgroundColor + .withOpacity(0.5), + child: SafeArea( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: 50, + height: 50, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: + Theme.of(context).colorScheme.primary, + width: 1.0, // Adjust the width as needed ), - SizedBox( - width: 10, + ), + child: CircleAvatar( + backgroundColor: Colors.transparent, + maxRadius: 10.0, + backgroundImage: user != null && + user.profilePhotoUrl != null + ? NetworkImage(user.profilePhotoUrl ?? '') + : null, + child: user != null && + user.profilePhotoUrl == null + ? Icon(Icons.person) + : null, + ), + ), + SizedBox( + width: 20, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Display the user's name + Text( + user != null ? user.username : 'Guest', + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + ), ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Display the user's name - Text( - user != null ? user.username : 'Guest', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.bold, - ), - ), - // Optionally, display additional user information like email - Text( - user != null ? user.email : '', - style: TextStyle( - fontSize: 13.0, - color: Theme.of(context).hintColor, - ), - ), - ], + Text( + user != null ? user.email : '', + style: TextStyle( + fontSize: 13.0, + color: Theme.of(context).hintColor, + ), ), ], ), - ), - ], + ], + ), ), ), - ); - }, - ), - ), - Divider( - height: 1, - color: Theme.of(context).hintColor.withOpacity(0.2), + ), + ); + }, ), + // Divider( + // height: 1, + // color: Theme.of(context).hintColor.withOpacity(0.2), + // ), Expanded( child: ListView( padding: EdgeInsets.zero, @@ -147,31 +145,17 @@ class CustomDrawer extends StatelessWidget { )); }, context: context), - // _buildListTileWithDecoration( - // title: 'Theme Color', - // icon: Icons.color_lens_outlined, - // onTap: () { - // Navigator.push( - // context, - // MaterialPageRoute( - // builder: (context) => ThemeSelectionScreen( - // onColorSelected: (Color) {}, - // ), - // )); - // }, - // context: context), _buildListTileWithDecoration( - title: Provider.of(context).themeData == - lightMode - ? 'Light Mode' - : 'Dark Mode', - icon: Provider.of(context).themeData == - lightMode - ? Icons.sunny - : Icons.dark_mode, + title: 'Theme', + icon: Icons.color_lens_outlined, onTap: () { - Provider.of(context, listen: false) - .toggleTheme(context); + // Navigator.push( + // context, + // MaterialPageRoute( + // builder: (context) => ThemeSelectionScreen( + // onColorSelected: (Color) {}, + // ), + // )); }, context: context), _buildListTileWithDecoration( @@ -223,7 +207,7 @@ class CustomDrawer extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - '© 2024 Alidantech co', + '© ${DateTime.now().year} Alidantech co', style: TextStyle( fontSize: 14.0, color: Theme.of(context).hintColor, diff --git a/lib/views/widgets/common/styled_container.dart b/lib/views/widgets/common/styled_container.dart new file mode 100644 index 0000000..32a8a4f --- /dev/null +++ b/lib/views/widgets/common/styled_container.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; + +class StyledContainer extends StatelessWidget { + final Widget child; + + const StyledContainer({Key? key, required this.child}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Theme.of(context).primaryColor.withOpacity(0.03), + border: Border.all( + color: Theme.of(context).primaryColor.withOpacity(0.5), + width: 0.5, + ), + ), + child: child, + ); + } +} \ No newline at end of file diff --git a/lib/views/widgets/common/tabs_appbar.dart b/lib/views/widgets/common/tabs_appbar.dart index c3af46f..1d46c8d 100644 --- a/lib/views/widgets/common/tabs_appbar.dart +++ b/lib/views/widgets/common/tabs_appbar.dart @@ -2,27 +2,43 @@ import 'package:flutter/material.dart'; class TabsAppBar extends StatelessWidget implements PreferredSizeWidget { final List tabs; - final Widget? title; + final String? title; + final List? actions; - const TabsAppBar({super.key, required this.tabs, this.title}); + const TabsAppBar({super.key, required this.tabs, this.title, this.actions}); @override Widget build(BuildContext context) { return AppBar( - backgroundColor: + shadowColor: Colors.transparent, + toolbarHeight: 40, + backgroundColor: Theme.of(context).scaffoldBackgroundColor.withOpacity(0.8), scrolledUnderElevation: 0.0, - title: title, + elevation: 0.0, + title: Padding( + padding: const EdgeInsets.only(left: 10), + child: Text( + title ?? "", + style: TextStyle(fontSize: 20, fontWeight: FontWeight.w400), + ), + ), + actions: actions, bottom: tabs.length > 0 ? TabBar( + padding: EdgeInsets.zero, + indicatorPadding: EdgeInsets.zero, labelColor: Theme.of(context).colorScheme.primary, indicatorColor: Theme.of(context).colorScheme.primary, unselectedLabelColor: Theme.of(context).hintColor, tabs: tabs, + dividerColor: + Theme.of(context).colorScheme.primary.withOpacity(0.2), + indicatorSize: TabBarIndicatorSize.tab, ) : null); } @override - Size get preferredSize => Size.fromHeight(kToolbarHeight); + Size get preferredSize => Size.fromHeight(100); } diff --git a/lib/views/widgets/dialogs/add_cartegory.dart b/lib/views/widgets/dialogs/add_cartegory.dart index c14c866..b03351f 100644 --- a/lib/views/widgets/dialogs/add_cartegory.dart +++ b/lib/views/widgets/dialogs/add_cartegory.dart @@ -1,165 +1,45 @@ -import 'package:Organiser/views/widgets/input/buttons.dart'; +import 'package:Organiser/views/widgets/common/custom_dialog.dart'; import 'package:flutter/material.dart'; class AddCategoryDialog { static Future show(BuildContext context) async { TextEditingController categoryController = TextEditingController(); - return showDialog( context: context, builder: (BuildContext context) { - return Dialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(35.0), - ), - child: Container( - margin: EdgeInsets.symmetric(horizontal: 30.0), - padding: EdgeInsets.symmetric(vertical: 20.0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.all(20.0), + return CustomDialog( + button1Text: 'Cancel', + button2Text: 'Done', + onButton1Pressed: () { + Navigator.pop(context); + }, + onButton2Pressed: () {}, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + Center( child: Text( - 'Add Category', - style: TextStyle( - fontSize: 18.0, - fontWeight: FontWeight.bold, - ), + 'Add Category', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + )), + SizedBox(height: 30), + TextField( + controller: categoryController, + style: TextStyle(fontSize: 16), + autocorrect: true, + + decoration: InputDecoration( + hintText: 'Category', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide.none, ), + fillColor: Theme.of(context).primaryColor.withOpacity(0.1), + filled: true, ), - AutocompleteBasiccategoryExample(), - SizedBox(height: 40.0), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - StyledButtons.secondaryOutlinedButton( - onPressed: () { - Navigator.of(context).pop(); - }, - icon: Icons.cancel_outlined, - context: context, - text: 'Cancel', - ), - Text('|'), - StyledButtons.primaryElevatedButton( - onPressed: () { - String category = categoryController.text.trim(); - if (category.isNotEmpty) { - Navigator.of(context).pop(category); - } - }, - text: 'Done', - icon: Icons.check, context: context, - ), - ], - ), - ], - ), - ), - ); - }, - ); - } -} - -@immutable -class Category { - const Category({ - required this.category, - }); - - final String category; - - @override - String toString() { - return '$category'; - } - - @override - bool operator ==(Object other) { - if (other.runtimeType != runtimeType) { - return false; - } - return other is Category && other.category == category; - } - - @override - int get hashCode => category.hashCode; -} - -class AutocompleteBasiccategoryExample extends StatelessWidget { - const AutocompleteBasiccategoryExample({Key? key}); - - static const List _categoryOptions = [ - Category(category: "Wedding"), - Category(category: "Birthday"), - Category(category: "Anniversary"), - Category(category: "Graduation"), - Category(category: "Corporate Event"), - Category(category: "Concert"), - Category(category: "Sports Event"), - Category(category: "Conference"), - Category(category: "Exhibition"), - Category(category: "Party"), - ]; - - static String _displayStringForOption(Category option) => option.category; - - @override - Widget build(BuildContext context) { - return RawAutocomplete( - // Pass the necessary parameters. - optionsBuilder: (TextEditingValue textEditingValue) { - if (textEditingValue.text == '') { - return const Iterable.empty(); - } - return _categoryOptions.where((Category option) { - return option - .toString() - .toLowerCase() - .contains(textEditingValue.text.toLowerCase()); - }); - }, - onSelected: (Category selection) { - debugPrint('You just selected ${_displayStringForOption(selection)}'); - }, - fieldViewBuilder: (BuildContext context, - TextEditingController textEditingController, - FocusNode focusNode, - VoidCallback onFieldSubmitted) { - return TextField( - controller: textEditingController, - focusNode: focusNode, - onSubmitted: (_) { - onFieldSubmitted(); - }, - ); - }, - optionsViewBuilder: (BuildContext context, - AutocompleteOnSelected onSelected, - Iterable options) { - // Return a widget to display the available options. - return Align( - alignment: Alignment.topLeft, - child: Material( - elevation: 4.0, - child: Container( - padding: EdgeInsets.zero, - constraints: BoxConstraints(maxHeight: 150, maxWidth: 310), - child: ListView( - children: options.map((Category option) { - return InkWell( - onTap: () { - onSelected(option); - }, - child: ListTile( - title: Text(_displayStringForOption(option)), - ), - ); - }).toList(), ), - ), + ], ), ); }, diff --git a/lib/views/widgets/dialogs/add_tag.dart b/lib/views/widgets/dialogs/add_tag.dart index 87e6b3d..74be15c 100644 --- a/lib/views/widgets/dialogs/add_tag.dart +++ b/lib/views/widgets/dialogs/add_tag.dart @@ -1,173 +1,89 @@ -import 'package:Organiser/views/widgets/input/buttons.dart'; +import 'package:Organiser/views/widgets/common/custom_dialog.dart'; import 'package:flutter/material.dart'; class AddTagDialog { - static List selectedTags = []; + static TextEditingController tagController = TextEditingController(); + static List tags = []; static Future?> show(BuildContext context) async { - //TextEditingController tagController = TextEditingController(); - return showDialog>( context: context, builder: (BuildContext context) { - return Dialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(25.0), - ), - child: Container( - margin: EdgeInsets.symmetric(horizontal: 30.0), - padding: EdgeInsets.symmetric(vertical: 10.0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.all(20.0), - child: Text( - 'Add Tag', - style: TextStyle( - fontSize: 18.0, - fontWeight: FontWeight.bold, - ), - ), - ), - Wrap( - spacing: 8.0, - children: AddTagDialog.selectedTags.map((tag) { - return Chip( - label: Text(tag.tag), - ); - }).toList(), - ), - AutocompleteBasicTagExample(), - SizedBox(height: 20.0), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - StyledButtons.secondaryOutlinedButton( - onPressed: () { - Navigator.of(context).pop(); - }, - icon: Icons.cancel_outlined, - context: context, - text: 'Cancel', - ), - Text('|'), - StyledButtons.secondaryOutlinedButton( - onPressed: () { - Navigator.of(context).pop(selectedTags); - }, - text: 'Done', - icon: Icons.check, context: context, - ), - ], - ), - ], - ), - ), - ); + return _buildDialog(context); }, ); } -} - -@immutable -class Tag { - const Tag({ - required this.tag, - }); - - final String tag; - - @override - String toString() { - return '$tag'; - } - @override - bool operator ==(Object other) { - if (other.runtimeType != runtimeType) { - return false; - } - return other is Tag && other.tag == Tag; - } - - @override - int get hashCode => tag.hashCode; -} - -class AutocompleteBasicTagExample extends StatelessWidget { - const AutocompleteBasicTagExample({Key? key}); - - static const List _TagOptions = [ - Tag(tag: "coding"), - Tag(tag: "Birthday"), - Tag(tag: "Anniversary"), - Tag(tag: "Graduation"), - Tag(tag: "Corporate"), - Tag(tag: "Concert"), - Tag(tag: "Sports Event"), - Tag(tag: "Conference"), - Tag(tag: "Exhibition"), - Tag(tag: "Party"), - ]; - - static String _displayStringForOption(Tag option) => option.tag; - - @override - Widget build(BuildContext context) { - return RawAutocomplete( - // Pass the necessary parameters. - optionsBuilder: (TextEditingValue textEditingValue) { - if (textEditingValue.text == '') { - return const Iterable.empty(); - } - return _TagOptions.where((Tag option) { - return option - .toString() - .toLowerCase() - .contains(textEditingValue.text.toLowerCase()); - }); - }, - onSelected: (Tag selection) { - if (!AddTagDialog.selectedTags.contains(selection)) { - AddTagDialog.selectedTags.add(selection); - } + static Widget _buildDialog(BuildContext context) { + return CustomDialog( + button1Text: 'Cancel', + button2Text: 'Done', + onButton1Pressed: () { + Navigator.pop(context); }, - fieldViewBuilder: (BuildContext context, tagController, - FocusNode focusNode, VoidCallback onFieldSubmitted) { - return TextField( - controller: tagController, - focusNode: focusNode, - onSubmitted: (_) { - onFieldSubmitted(); - }, - ); + onButton2Pressed: () { + Navigator.pop(context, tags); }, - optionsViewBuilder: (BuildContext context, - AutocompleteOnSelected onSelected, Iterable options) { - return Align( - alignment: Alignment.topLeft, - child: Material( - elevation: 4.0, - child: Container( - padding: EdgeInsets.zero, - constraints: BoxConstraints(maxHeight: 150, maxWidth: 310), - child: ListView( - children: options.map((Tag option) { - return InkWell( - onTap: () { - onSelected(option); - }, - child: ListTile( - title: Text(_displayStringForOption(option)), - ), - ); - }).toList(), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Add Tags', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + textAlign: TextAlign.center, + ), + SizedBox(height: 10), + Wrap( + spacing: 8.0, + runSpacing: 4.0, + children: [ + for (var tag in tags) + _buildTagChip(tag, () { + tags.remove(tag); + }), + ], + ), + SizedBox(height: 10), + TextField( + controller: tagController, + style: TextStyle(fontSize: 16), + autocorrect: true, + onChanged: (value) { + if (value.endsWith(' ')) { + final tag = value.trim(); + if (tag.isNotEmpty) { + tags.add(tag); + tagController.clear(); + } + } + }, + decoration: InputDecoration( + hintText: 'Add tag', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide.none, ), + fillColor: Theme.of(context).primaryColor.withOpacity(0.1), + filled: true, ), ), - ); - }, + ], + ), + ); + } + + static Widget _buildTagChip(String tag, VoidCallback onCancel) { + return InputChip( + label: Text(tag), + onDeleted: onCancel, + padding: EdgeInsets.only(left: 2, right: 0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30), + side: BorderSide(color: Colors.blue, width: 1.5), + ), + deleteIcon: Icon(Icons.cancel), + deleteButtonTooltipMessage: 'Remove $tag', ); } } diff --git a/lib/views/widgets/input/auto_complete.dart b/lib/views/widgets/input/auto_complete.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/views/widgets/input/buttons.dart b/lib/views/widgets/input/buttons.dart deleted file mode 100644 index ddc0ca1..0000000 --- a/lib/views/widgets/input/buttons.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:flutter/material.dart'; - -class StyledButtons { - static Widget primaryElevatedButton({ - required VoidCallback onPressed, - required String text, - required BuildContext context, - IconData? icon, - double borderRadius = 35.0, - double horizontalPadding = 16.0, - double verticalPadding = 8.0, - }) { - return ElevatedButton.icon( - onPressed: onPressed, - icon: Icon(icon), - label: Text(text), - style: ElevatedButton.styleFrom( - elevation: 0, - backgroundColor: - Theme.of(context).colorScheme.secondary.withOpacity(0.2), - foregroundColor: Theme.of(context).colorScheme.primary, - padding: EdgeInsets.symmetric( - horizontal: horizontalPadding, - vertical: verticalPadding, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(borderRadius), - ), - ), - ); - } - - static Widget secondaryOutlinedButton({ - required BuildContext context, - required VoidCallback onPressed, - required String text, - IconData? icon, - double borderRadius = 55.0, - double horizontalPadding = 0, - double verticalPadding = 0, - }) { - return OutlinedButton( - - onPressed: onPressed, - style: OutlinedButton.styleFrom( - padding: EdgeInsets.zero, - side: BorderSide(color: Theme.of(context).colorScheme.primary), - shape: RoundedRectangleBorder( - side: BorderSide(), - borderRadius: BorderRadius.circular(borderRadius), - ), - ), child: Text(text), - ); - } -} diff --git a/lib/views/widgets/input/description.dart b/lib/views/widgets/input/description.dart deleted file mode 100644 index 8b94eda..0000000 --- a/lib/views/widgets/input/description.dart +++ /dev/null @@ -1,116 +0,0 @@ -import 'package:flutter/material.dart'; - -class DescriptionEditorPage extends StatefulWidget { - @override - _DescriptionEditorPageState createState() => _DescriptionEditorPageState(); -} - -class _DescriptionEditorPageState extends State { - //TextEditingController _controller = TextEditingController(); - - @override - Widget build(BuildContext context) { - // Get the screen size - Size screenSize = MediaQuery.of(context).size; - - // Set preferred width and height (adjust these based on user preferences) - double preferredHeight = screenSize.height * 0.5; - - return Dialog( - elevation: 0, - insetPadding: EdgeInsets.symmetric(horizontal: 10.0), - child: SizedBox( - height: preferredHeight, - width: double.infinity, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Expanded( - child: SingleChildScrollView( - padding: EdgeInsets.symmetric(horizontal: 10), - child: TextField( - decoration: InputDecoration( - border: InputBorder.none - ), - maxLines: 100, - autofocus: true, - ), - ), - ), - Card( - margin: EdgeInsets.zero, - elevation: 20, - shadowColor: Colors.black, - color: Theme.of(context).colorScheme.secondary, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - IconButton( - icon: Icon(Icons.format_bold), - onPressed: () { - // Handle bold button press - }, - ), - IconButton( - icon: Icon(Icons.format_italic), - onPressed: () { - // Handle italic button press - }, - ), - IconButton( - icon: Icon(Icons.format_underlined), - onPressed: () { - // Handle underline button press - }, - ), - IconButton( - icon: Icon(Icons.format_list_bulleted), - onPressed: () { - // Handle bullet list button press - }, - ), - IconButton( - icon: Icon(Icons.format_list_numbered), - onPressed: () { - // Handle numbered list button press - }, - ), - IconButton( - icon: Icon(Icons.link), - onPressed: () { - // Handle link button press - }, - ), - ]), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - TextButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text('CANCEL'), - ), - TextButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text('SAVE'), - ), - ], - ), - ), - ], - ), - ) - ], - ), - ), - ); - } -} diff --git a/lib/views/widgets/input/dropdown.dart b/lib/views/widgets/input/dropdown.dart deleted file mode 100644 index 39d85c0..0000000 --- a/lib/views/widgets/input/dropdown.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:flutter/material.dart'; - -class StyledDropdown extends StatelessWidget { - final String selectedValue; - final List items; - final void Function(String) onChanged; - - StyledDropdown({ - required this.selectedValue, - required this.items, - required this.onChanged, - }); - - @override - Widget build(BuildContext context) { - return DropdownButtonFormField( - value: selectedValue, - menuMaxHeight: 250, - borderRadius: BorderRadius.all(Radius.circular(5)), - - items: items.map((String value) { - return DropdownMenuItem( - value: value, - child: Text(value), - ); - }).toList(), - onChanged: (value) => selectedValue, - decoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(5.0), - ), - ), - ); - } -} diff --git a/lib/views/widgets/input/input/tag_chips.dart b/lib/views/widgets/input/input/tag_chips.dart deleted file mode 100644 index 6dff0de..0000000 --- a/lib/views/widgets/input/input/tag_chips.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'package:Organiser/views/widgets/input/buttons.dart'; -import 'package:flutter/material.dart'; - -class TagChips extends StatefulWidget { - @override - _TagChipsState createState() => _TagChipsState(); -} - -class _TagChipsState extends State { - List tags = []; - TextEditingController tagController = TextEditingController(); - bool isAddingTag = false; - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Wrap( - children: tags.map((tag) => _buildChip(tag)).toList(), - ), - SizedBox(height: 8.0), - isAddingTag ? _buildTagInput() : _buildAddButton(), - ], - ); - } - - Widget _buildChip(String tag) { - return Chip( - label: Text(tag), - onDeleted: () { - _removeTag(tag); - }, - ); - } - - Widget _buildAddButton() { - return Row( - children: [ - StyledButtons.primaryElevatedButton( - onPressed: () { - setState(() { - isAddingTag = true; - }); - }, - text: 'Add tags', - icon: Icons.add, context: context, - ), - ], - ); - } - - - - Widget _buildTagInput() { - return Row( - children: [ - Expanded( - child: TextField( - controller: tagController, - decoration: InputDecoration(labelText: 'Tag'), - onSubmitted: (value) { - _addTag(value); - }, - ), - ), - IconButton( - icon: Icon(Icons.check), - onPressed: () { - _addTag(tagController.text); - }, - ), - IconButton( - icon: Icon(Icons.cancel), - onPressed: () { - setState(() { - isAddingTag = false; - tagController.clear(); - }); - }, - ), - ], - ); - } - - void _addTag(String tag) { - if (tag.isNotEmpty && !tags.contains(tag)) { - setState(() { - tags.add(tag); - isAddingTag = false; - tagController.clear(); - }); - } - } - - void _removeTag(String tag) { - setState(() { - tags.remove(tag); - }); - } -} diff --git a/lib/views/widgets/input/pickers.dart b/lib/views/widgets/input/pickers.dart deleted file mode 100644 index c324f0f..0000000 --- a/lib/views/widgets/input/pickers.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:flutter/material.dart'; - -class DatePickerUtil { - static Future pickDate( - BuildContext context, DateTime initialDate) async { - DateTime? pickedDate = await showDatePicker( - context: context, - initialDate: initialDate, - firstDate: DateTime(2000), - lastDate: DateTime(2101), - ); - - return pickedDate; - } -} diff --git a/lib/views/widgets/input/tag_chips.dart b/lib/views/widgets/input/tag_chips.dart deleted file mode 100644 index 6dff0de..0000000 --- a/lib/views/widgets/input/tag_chips.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'package:Organiser/views/widgets/input/buttons.dart'; -import 'package:flutter/material.dart'; - -class TagChips extends StatefulWidget { - @override - _TagChipsState createState() => _TagChipsState(); -} - -class _TagChipsState extends State { - List tags = []; - TextEditingController tagController = TextEditingController(); - bool isAddingTag = false; - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Wrap( - children: tags.map((tag) => _buildChip(tag)).toList(), - ), - SizedBox(height: 8.0), - isAddingTag ? _buildTagInput() : _buildAddButton(), - ], - ); - } - - Widget _buildChip(String tag) { - return Chip( - label: Text(tag), - onDeleted: () { - _removeTag(tag); - }, - ); - } - - Widget _buildAddButton() { - return Row( - children: [ - StyledButtons.primaryElevatedButton( - onPressed: () { - setState(() { - isAddingTag = true; - }); - }, - text: 'Add tags', - icon: Icons.add, context: context, - ), - ], - ); - } - - - - Widget _buildTagInput() { - return Row( - children: [ - Expanded( - child: TextField( - controller: tagController, - decoration: InputDecoration(labelText: 'Tag'), - onSubmitted: (value) { - _addTag(value); - }, - ), - ), - IconButton( - icon: Icon(Icons.check), - onPressed: () { - _addTag(tagController.text); - }, - ), - IconButton( - icon: Icon(Icons.cancel), - onPressed: () { - setState(() { - isAddingTag = false; - tagController.clear(); - }); - }, - ), - ], - ); - } - - void _addTag(String tag) { - if (tag.isNotEmpty && !tags.contains(tag)) { - setState(() { - tags.add(tag); - isAddingTag = false; - tagController.clear(); - }); - } - } - - void _removeTag(String tag) { - setState(() { - tags.remove(tag); - }); - } -} diff --git a/lib/views/widgets/input/textfields.dart b/lib/views/widgets/input/textfields.dart deleted file mode 100644 index e3c5c1a..0000000 --- a/lib/views/widgets/input/textfields.dart +++ /dev/null @@ -1,204 +0,0 @@ -import 'package:flutter/material.dart'; - -class StyledTextField extends StatelessWidget { - final TextEditingController controller; - final String label; - final bool isMultiline; - final int maxLines; - final void Function(String)? onChanged; - final String? Function(String?)? validator; - final IconData? leadingIcon; - final IconData? trailingIcon; - final void Function()? onLeadingIconTap; - final void Function()? onTrailingIconTap; - final TextInputType? inputType; - final double? paddingX; - final double? paddingY; - final double? textSize; - final Color? iconColor; - - StyledTextField({ - required this.controller, - required this.label, - this.iconColor, - this.isMultiline = false, - this.maxLines = 1, - this.onChanged, - this.validator, - this.leadingIcon, - this.trailingIcon, - this.onLeadingIconTap, - this.onTrailingIconTap, - this.inputType, - this.paddingX = 10.0, - this.paddingY = 20.0, - this.textSize = 15, - }); - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - _buildRegularTextField(context), - ], - ); - } - - Widget _buildRegularTextField(BuildContext context) { - return Container( - padding: EdgeInsets.symmetric(horizontal: paddingX!, vertical: paddingY!), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.secondary.withOpacity(0.2), - borderRadius: BorderRadius.circular(15.0), - ), - child: Expanded( - child: Center( - child: TextField( - style: TextStyle( - fontSize: textSize, - ), - decoration: InputDecoration( - hintText: label, - hintStyle: TextStyle( - fontSize: textSize, fontWeight: FontWeight.normal), - border: InputBorder.none, - suffixIcon: Icon( - trailingIcon, - color: iconColor, - )), - keyboardType: inputType, - ), - ), - ), - ); - } -} - -class BottomBorderTextField extends StatelessWidget { - final TextEditingController controller; - final String hintText; - final IconData? leadingIcon; - final IconData? trailingIcon; - final TextInputType inputType; - - BottomBorderTextField({ - required this.controller, - required this.hintText, - this.leadingIcon, - this.trailingIcon, - this.inputType = TextInputType.text, - }); - - @override - Widget build(BuildContext context) { - return Container( - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Theme.of(context).colorScheme.primary, - width: 0.0, - ), - ), - ), - child: TextField( - controller: controller, - keyboardType: inputType, - decoration: InputDecoration( - hintText: hintText, - prefixIcon: Icon(leadingIcon), - suffixIcon: Icon(trailingIcon), - border: InputBorder.none, - ), - ), - ); - } -} - -class AutocompleteTextField extends StatelessWidget { - final TextEditingController controller; - final String label; - final List autocompleteList; - final String? Function(T?) autocompleteLabelBuilder; - final void Function(T?)? onAutocompleteSelected; - final IconData? leadingIcon; - final IconData? trailingIcon; - final void Function()? onLeadingIconTap; - final void Function()? onTrailingIconTap; - - AutocompleteTextField({ - required this.controller, - required this.label, - required this.autocompleteList, - required this.autocompleteLabelBuilder, - this.onAutocompleteSelected, - this.leadingIcon, - this.trailingIcon, - this.onLeadingIconTap, - this.onTrailingIconTap, - }); - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - _buildAutocompleteTextField(), - ], - ); - } - - Widget _buildAutocompleteTextField() { - return Autocomplete( - optionsBuilder: (TextEditingValue textEditingValue) { - return autocompleteList - .where((item) => autocompleteLabelBuilder(item)! - .toLowerCase() - .contains(textEditingValue.text.toLowerCase())) - .toList(); - }, - onSelected: onAutocompleteSelected, - fieldViewBuilder: (BuildContext context, - TextEditingController textEditingController, - FocusNode focusNode, - VoidCallback onFieldSubmitted) { - return StyledTextField( - controller: textEditingController, - isMultiline: false, - maxLines: 1, - onChanged: (value) {}, - validator: (value) { - return null; - }, - leadingIcon: leadingIcon, - trailingIcon: trailingIcon, - onLeadingIconTap: onLeadingIconTap, - onTrailingIconTap: onTrailingIconTap, - label: label, - ); - }, - optionsViewBuilder: (BuildContext context, - AutocompleteOnSelected onSelected, Iterable options) { - return Align( - alignment: Alignment.topLeft, - child: Material( - elevation: 4.0, - child: Container( - constraints: BoxConstraints(maxHeight: 200), - child: ListView( - children: options - .map((item) => ListTile( - title: Text(autocompleteLabelBuilder(item) ?? ''), - onTap: () { - onSelected(item); - }, - )) - .toList(), - ), - ), - ), - ); - }, - ); - } -} diff --git a/lib/views/widgets/styled/form_fields/dropdown.dart b/lib/views/widgets/styled/form_fields/dropdown.dart new file mode 100644 index 0000000..660a617 --- /dev/null +++ b/lib/views/widgets/styled/form_fields/dropdown.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; + +typedef CustomValueCallback = Future Function(BuildContext context); + +class FormDropDown extends StatelessWidget { + final String labelText; + final T value; + final List items; + final void Function(T?) onChanged; + final bool required; + final List customValueOptions; + final CustomValueCallback onCustomValueSelected; + + FormDropDown({ + required this.labelText, + required this.value, + required this.items, + required this.onChanged, + required this.customValueOptions, + required this.onCustomValueSelected, + this.required = false, + }); + + Future _handleCustomValueSelection(BuildContext context) async { + final T? customValue = await onCustomValueSelected(context); + if (customValue != null) { + onChanged(customValue); + } + } + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + labelText, + style: TextStyle( + color: Theme.of(context).primaryColor, + ), + ), + DropdownButtonFormField( + isExpanded: false, + elevation: 1, + icon: Icon(Icons.arrow_drop_down_circle_outlined), + padding: EdgeInsets.all(4), + value: value, + focusColor: Theme.of(context).primaryColor.withOpacity(0.1), + enableFeedback: true, + dropdownColor: Theme.of(context).scaffoldBackgroundColor.withOpacity(0.97), + borderRadius: BorderRadius.circular(10), + decoration: InputDecoration( + filled: true, + fillColor: Theme.of(context).primaryColor.withOpacity(0.1), + border: OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(8.0), + ), + contentPadding: EdgeInsets.symmetric(vertical: 16.0, horizontal: 12.0), + ), + onChanged: (T? newValue) async { + if (customValueOptions.contains(newValue)) { + await _handleCustomValueSelection(context); + } else { + onChanged(newValue); + } + }, + validator: (value) { + if (required && (value == null || value.toString().isEmpty)) { + return 'Please select a $labelText'; + } + return null; + }, + items: items.map>((T item) { + final String text = item.toString().split('.').last; + final String capitalizedText = text[0].toUpperCase() + text.substring(1); + return DropdownMenuItem( + value: item, + child: Text( + capitalizedText, + style: TextStyle(), + ), + ); + }).toList(), + ), + ], + ); + } +} diff --git a/lib/views/widgets/styled/form_fields/files_upload.dart b/lib/views/widgets/styled/form_fields/files_upload.dart new file mode 100644 index 0000000..eb28435 --- /dev/null +++ b/lib/views/widgets/styled/form_fields/files_upload.dart @@ -0,0 +1,164 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:file_picker/file_picker.dart'; + +class FileUploadDropZone extends StatefulWidget { + final String title; + final TextEditingController controller; + const FileUploadDropZone({ + Key? key, + required this.title, + required this.controller, + }) : super(key: key); + + @override + _FileUploadDropZoneState createState() => _FileUploadDropZoneState(); +} + +class _FileUploadDropZoneState extends State { + List _files = []; + + @override + void initState() { + super.initState(); + _files = widget.controller.text.isEmpty + ? [] + : widget.controller.text.split(',').map((path) => File(path)).toList(); + } + + void _pickFiles() async { + if (_files.length >= 3) return; + + try { + FilePickerResult? result = await FilePicker.platform.pickFiles( + type: FileType.custom, + allowedExtensions: ['pdf', 'doc', 'docx', 'jpg', 'jpeg', 'png'], + allowMultiple: true, + ); + + if (result != null) { + List pickedFiles = result.files; + + List validFiles = pickedFiles + .where((file) { + return file.size <= 1 * 1024 * 1024; // File size limit: 1MB + }) + .map((file) => File(file.path!)) + .toList(); + + if (validFiles.length + _files.length > 3) { + validFiles = validFiles.sublist(0, 3 - _files.length); + } + + setState(() { + _files.addAll(validFiles); + }); + + widget.controller.text = _files.map((file) => file.path).join(','); + } + } catch (e) { + print("File picking failed: $e"); + } + } + + void _removeFile(int index) { + setState(() { + _files.removeAt(index); + }); + + widget.controller.text = _files.map((file) => file.path).join(','); + } + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text( + widget.title, + style: TextStyle( + color: Theme.of(context).primaryColor, + ), + ), + Container( + width: double.infinity, + padding: EdgeInsets.symmetric(vertical: 12, horizontal: 10), + margin: EdgeInsets.zero, + decoration: BoxDecoration( + color: Theme.of(context).primaryColor.withOpacity(0.1), + border: Border.all( + width: 2, + color: Theme.of(context).primaryColor.withOpacity(0.1)), + borderRadius: BorderRadius.circular(8.0), + ), + child: _files.isEmpty + ? GestureDetector( + onTap: _pickFiles, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.cloud_upload, + size: 35.0, color: Theme.of(context).primaryColor), + SizedBox(height: 8.0), + Text( + 'Tap to upload files\nMaximum size 1MB', + textAlign: TextAlign.center, + style: TextStyle( + color: Theme.of(context).primaryColor, + fontWeight: FontWeight.bold, + fontSize: 12), + ), + ], + ), + ) + : Row( + children: [ + Expanded( + child: Wrap( + spacing: 8.0, + children: List.generate(_files.length, (index) { + File file = _files[index]; + return Stack( + children: [ + Container( + width: 60, + height: 60, + decoration: BoxDecoration( + color: Theme.of(context) + .primaryColor + .withOpacity(0.1), + borderRadius: BorderRadius.circular(8.0), + image: DecorationImage( + image: FileImage(file), + fit: BoxFit.cover, + ), + ), + ), + Positioned( + top: -5, + right: -5, + child: IconButton( + icon: Icon(Icons.remove_circle, + color: Colors.red, size: 20), + onPressed: () => _removeFile(index), + ), + ), + ], + ); + }), + ), + ), + if (_files.length < 3) + IconButton( + icon: Icon(Icons.add_circle, + color: Theme.of(context).primaryColor, size: 30), + onPressed: _pickFiles, + ), + ], + ), + ), + ], + ); + } +} diff --git a/lib/views/widgets/styled/input_adder/optionsAppBar.dart b/lib/views/widgets/styled/form_fields/options_appbar.dart similarity index 96% rename from lib/views/widgets/styled/input_adder/optionsAppBar.dart rename to lib/views/widgets/styled/form_fields/options_appbar.dart index a7d0341..e090456 100644 --- a/lib/views/widgets/styled/input_adder/optionsAppBar.dart +++ b/lib/views/widgets/styled/form_fields/options_appbar.dart @@ -33,7 +33,7 @@ class OptionsAppBar extends StatelessWidget { children: [ Padding( padding: const EdgeInsets.symmetric( - horizontal: 40.0, vertical: 15), + horizontal: 40.0, vertical: 5), child: Text( this.cancelTitle, style: TextStyle(fontSize: 18), @@ -50,7 +50,7 @@ class OptionsAppBar extends StatelessWidget { }, child: Padding( padding: - const EdgeInsets.symmetric(horizontal: 40.0, vertical: 15), + const EdgeInsets.symmetric(horizontal: 40.0, vertical: 5), child: Text( this.AcceptTitle, style: TextStyle(fontSize: 18), diff --git a/lib/views/widgets/styled/form_fields/segmented_control.dart b/lib/views/widgets/styled/form_fields/segmented_control.dart new file mode 100644 index 0000000..16b6df6 --- /dev/null +++ b/lib/views/widgets/styled/form_fields/segmented_control.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; + +class SegmentedControl extends StatelessWidget { + final Map segments; + final int currentValue; + final ValueChanged? onChanged; + final double borderRadius; + final double paddingVertical; + final String title; + + SegmentedControl({ + required this.segments, + required this.currentValue, + this.onChanged, + this.borderRadius = 10.0, + this.paddingVertical = 12.0, + required this.title, + }); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 8.0), + child: Text( + title, // Replace with your desired label text + style: TextStyle( + color: Theme.of(context).primaryColor, + ), + ), + ), + Container( + width: double.infinity, + decoration: BoxDecoration( + color: Theme.of(context).primaryColor.withOpacity(0.1), + borderRadius: BorderRadius.circular(borderRadius), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment + .spaceEvenly, // Ensure even distribution of segments + children: segments.entries.map((entry) { + return Expanded( + // Ensure each segment takes equal space + child: GestureDetector( + onTap: () { + onChanged?.call(entry.key); + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: paddingVertical, horizontal: 16.0), + decoration: BoxDecoration( + color: entry.key == currentValue + ? Theme.of(context).primaryColor.withOpacity(0.5) + : Colors.transparent, + borderRadius: BorderRadius.horizontal( + left: entry.key == 0 + ? Radius.circular(borderRadius) + : Radius.zero, + right: entry.key == segments.length - 1 + ? Radius.circular(borderRadius) + : Radius.zero, + ), + ), + child: Center(child: entry.value), + ), + ), + ); + }).toList(), + ), + ), + ], + ); + } +} diff --git a/lib/views/widgets/styled/form_fields/sub_tasks_field.dart b/lib/views/widgets/styled/form_fields/sub_tasks_field.dart new file mode 100644 index 0000000..affbe1c --- /dev/null +++ b/lib/views/widgets/styled/form_fields/sub_tasks_field.dart @@ -0,0 +1,187 @@ +import 'package:Organiser/views/widgets/styled/form_fields/text_field.dart'; +import 'package:flutter/material.dart'; +import 'package:Organiser/models/enums/task_enums.dart'; + +class SubtaskWidget extends StatefulWidget { + final Map? subtasks; + final ValueChanged?>? onChanged; + + SubtaskWidget({this.subtasks, this.onChanged}); + + @override + _SubtaskWidgetState createState() => _SubtaskWidgetState(); +} + +class _SubtaskWidgetState extends State { + TextEditingController _titleController = TextEditingController(); + TaskStatus _status = TaskStatus.todo; + bool _isAddingSubtask = false; + bool _canAddSubtask = false; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Sub Tasks", + style: TextStyle( + color: Theme.of(context).primaryColor, + fontSize: 16.0, + fontWeight: FontWeight.bold, + ), + ), + IconButton( + icon: Icon(_isAddingSubtask ? Icons.cancel : Icons.add), + onPressed: () { + setState(() { + _isAddingSubtask = !_isAddingSubtask; + }); + }, + ), + ], + ), + if (widget.subtasks != null && widget.subtasks!.isNotEmpty) ...[ + Container( + decoration: BoxDecoration( + color: Theme.of(context).primaryColor.withOpacity(0.1), + border: Border.all( + color: Theme.of(context).primaryColor.withOpacity(0.1), + width: 0.5, + ), + borderRadius: BorderRadius.circular(10.0), + ), + child: Column( + children: [ + for (var entry in widget.subtasks!.entries) + _buildSubtaskItem( + entry.key, + entry.value, + ), + ], + )), + ], + SizedBox(height: 8.0), + if (_isAddingSubtask) + Row( + children: [ + Expanded( + child: FormTextField( + controller: _titleController, + autofocus: true, + onChanged: (value) { + setState(() { + _canAddSubtask = value.trim().isNotEmpty; + }); + }, + labelText: 'New Subtask', + suffix: _canAddSubtask + ? IconButton( + icon: Icon(Icons.check, + color: Theme.of(context).primaryColor), + onPressed: _addSubtask, + ) + : null, + ), + ), + ], + ), + ], + ); + } + + Widget _buildSubtaskItem(String title, TaskStatus status) { + return Container( + decoration: BoxDecoration( + color: Colors.transparent, + border: Border( + bottom: BorderSide( + color: Theme.of(context).primaryColor.withOpacity(0.1), + width: 0.5, + ), + ), + ), + child: ListTile( + title: Text(title), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + margin: EdgeInsets.symmetric(vertical: 8.0), + padding: EdgeInsets.symmetric(horizontal: 8.0), + decoration: BoxDecoration( + color: Theme.of(context).primaryColor.withOpacity(0.1), + borderRadius: BorderRadius.circular(15.0), + border: Border.all( + color: Theme.of(context).primaryColor.withOpacity(0.5), + width: 0.5, + ), + ), + child: DropdownButton( + style: TextStyle(color: Theme.of(context).primaryColor), + underline: Container( ), + elevation: 0, + borderRadius: BorderRadius.circular(8.0), + value: status, + icon: Icon(Icons.arrow_drop_down_sharp), + onChanged: (TaskStatus? newStatus) { + if (newStatus != null) { + _updateSubtaskStatus(title, newStatus); + } + }, + items: TaskStatus.values + .where((status) => status != TaskStatus.archived) + .map((TaskStatus status) { + return DropdownMenuItem( + value: status, + child: Text(status.toString().split('.').last), + ); + }).toList(), + ), + ), + IconButton( + icon: Icon(Icons.remove_circle, color: Colors.red), + onPressed: () { + _removeSubtask(title); + }, + ), + ], + ), + ), + ); + } + + void _addSubtask() { + String title = _titleController.text.trim(); + if (title.isNotEmpty) { + widget.subtasks?[title] = _status; + _titleController.clear(); + setState(() { + _canAddSubtask = false; + _isAddingSubtask = false; + }); + if (widget.onChanged != null) { + widget.onChanged!(widget.subtasks); + } + } + } + + void _updateSubtaskStatus(String title, TaskStatus status) { + widget.subtasks?[title] = status; + setState(() {}); + if (widget.onChanged != null) { + widget.onChanged!(widget.subtasks); + } + } + + void _removeSubtask(String title) { + widget.subtasks?.remove(title); + setState(() {}); + if (widget.onChanged != null) { + widget.onChanged!(widget.subtasks); + } + } +} diff --git a/lib/views/widgets/styled/form_fields/text_field.dart b/lib/views/widgets/styled/form_fields/text_field.dart index e69de29..9207d2b 100644 --- a/lib/views/widgets/styled/form_fields/text_field.dart +++ b/lib/views/widgets/styled/form_fields/text_field.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; + +class FormTextField extends StatelessWidget { + final String labelText; + final TextEditingController controller; + final String? placeholder; + final String? Function(String?)? validator; + final bool required; + final Widget? suffix; + final bool? obscureText; + final TextInputType? keyboardType; + final Widget? prefix; + final ValueChanged? onChanged; + final bool? enabled; + final bool? readOnly; + final int? maxLines; + final bool? autofocus; + + FormTextField({ + required this.labelText, + required this.controller, + this.placeholder, + this.validator, + this.required = false, + this.suffix, + this.obscureText, + this.keyboardType, + this.prefix, + this.onChanged, + this.enabled, + this.readOnly, + this.maxLines, + this.autofocus, + }); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + labelText, + style: TextStyle( + color: theme.primaryColor, + ), + ), + TextFormField( + enabled: enabled ?? true, + readOnly: readOnly ?? false, + maxLines: maxLines ?? 1, + autofocus: autofocus ?? false, + controller: controller, + validator: (value) { + if (required && (value == null || value.isEmpty)) { + return 'Please enter $labelText'; + } + if (validator != null) { + return validator!(value); + } + return null; + }, + obscureText: obscureText ?? false, + keyboardType: keyboardType ?? TextInputType.text, + onChanged: onChanged, + decoration: InputDecoration( + filled: true, + fillColor: theme.primaryColor.withOpacity(0.1), + contentPadding: const EdgeInsets.symmetric( + vertical: 16.0, + horizontal: 16.0, + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.0), + borderSide: BorderSide.none, + ), + hintText: placeholder ?? labelText, + suffixIcon: suffix, + suffixIconColor: Theme.of(context).primaryColor, + suffixStyle: TextStyle( + color: Theme.of(context).primaryColor, + fontSize: 16.0, + ), + prefixIcon: prefix, + ), + ), + ], + ); + } +} diff --git a/lib/views/widgets/styled/input_adder/cartegory.dart b/lib/views/widgets/styled/input_adder/cartegory.dart deleted file mode 100644 index 4914c32..0000000 --- a/lib/views/widgets/styled/input_adder/cartegory.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:Organiser/views/widgets/dialogs/add_cartegory.dart'; -import 'package:Organiser/views/widgets/input/buttons.dart'; -import 'package:flutter/material.dart'; - -class CartegoryAdder extends StatelessWidget { - final TextEditingController cartegoryController; - - CartegoryAdder({required this.cartegoryController}); - - @override - Widget build(BuildContext context) { - return StyledButtons.primaryElevatedButton( - onPressed: () async { - String? result = await AddCategoryDialog.show(context); - if (result != null) {} - }, - text: 'Cartegory', - icon: Icons.post_add_rounded, - context: context, - verticalPadding: 0, - ); - } -} diff --git a/lib/views/widgets/styled/input_adder/cartegory_adder.dart b/lib/views/widgets/styled/input_adder/cartegory_adder.dart deleted file mode 100644 index 4914c32..0000000 --- a/lib/views/widgets/styled/input_adder/cartegory_adder.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:Organiser/views/widgets/dialogs/add_cartegory.dart'; -import 'package:Organiser/views/widgets/input/buttons.dart'; -import 'package:flutter/material.dart'; - -class CartegoryAdder extends StatelessWidget { - final TextEditingController cartegoryController; - - CartegoryAdder({required this.cartegoryController}); - - @override - Widget build(BuildContext context) { - return StyledButtons.primaryElevatedButton( - onPressed: () async { - String? result = await AddCategoryDialog.show(context); - if (result != null) {} - }, - text: 'Cartegory', - icon: Icons.post_add_rounded, - context: context, - verticalPadding: 0, - ); - } -} diff --git a/lib/views/widgets/styled/input_adder/chips.dart b/lib/views/widgets/styled/input_adder/chips.dart deleted file mode 100644 index 585b801..0000000 --- a/lib/views/widgets/styled/input_adder/chips.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:flutter/material.dart'; - -// ignore: must_be_immutable -class SelectableChip extends StatefulWidget { - final String label; - bool isSelected = false; - bool showAvatar = false; - - SelectableChip({required this.label}); - - @override - _SelectableChipState createState() => _SelectableChipState(); -} - -class _SelectableChipState extends State { - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - ChoiceChip( - backgroundColor: Colors.transparent, - label: Text(widget.label), - selected: widget.isSelected, - onSelected: (selected) { - setState(() { - widget.isSelected = selected; - }); - }, - selectedColor: Theme.of(context).colorScheme.secondary, - - ), - if (widget.showAvatar) - CircleAvatar( - backgroundColor: Theme.of(context).colorScheme.secondary, - child: Icon( - Icons.check, - color: Colors.white, - ), - ), - ], - ), - ); - } -} diff --git a/lib/views/widgets/styled/input_adder/date.dart b/lib/views/widgets/styled/input_adder/date.dart deleted file mode 100644 index e633179..0000000 --- a/lib/views/widgets/styled/input_adder/date.dart +++ /dev/null @@ -1,133 +0,0 @@ -// date_picker.dart -import 'package:flutter/material.dart'; - -// ignore: must_be_immutable -class DateAdder extends StatefulWidget { - final DateTime? dateController; - final DateTime? startDateController; - final DateTime? endDateController; - bool isMultiDayController; - - DateAdder({ - this.dateController, - this.endDateController, - this.startDateController, - required this.isMultiDayController, - }); - - @override - _DateAdder createState() => _DateAdder(); -} - -class _DateAdder extends State { - Future _selectDate(BuildContext context) async { - DateTime? pickedDate = await showDatePicker( - context: context, - initialDate: widget.dateController!, - firstDate: DateTime(2000), - lastDate: DateTime(2101), - ); - - if (pickedDate != null && pickedDate != widget.dateController) { - onDateSelected(pickedDate); - } - } - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: () => _selectDate(context), - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(25.0), - ), - margin: EdgeInsets.zero, - elevation: 0, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 15.0, horizontal: 5), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SizedBox( - width: 10, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - if (widget.isMultiDayController) Text( - 'BEGIN:', - style: TextStyle( - fontSize: 10, fontWeight: FontWeight.w300), - ), - SizedBox( - width: 8, - ), - Text( - 'Wen, 24 Jan', - style: TextStyle( - color: Theme.of(context).hintColor, - fontSize: 24, - fontWeight: FontWeight.w400), - ), - ], - ), - if(widget.isMultiDayController) SizedBox( - height: 10, - ), - if (widget.isMultiDayController) - GestureDetector( - onTap: () => _selectDate(context), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'ENDS:', - style: TextStyle( - fontSize: 10, fontWeight: FontWeight.w300), - ), - SizedBox( - width: 10, - ), - Text( - 'Thu, 25 Jan', - style: TextStyle( - fontSize: 24, - color: Theme.of(context).hintColor, - fontWeight: FontWeight.w400), - ), - ], - ), - ), - ], - ), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('Multiple Days'), - Switch( - value: widget.isMultiDayController, - onChanged: (bool newValue) { - setState(() { - widget.isMultiDayController = newValue; - }); - }, - ), - ], - ), - ], - ), - ), - ), - ); - } -} - -void onDateSelected(DateTime pickedDate) {} diff --git a/lib/views/widgets/styled/input_adder/date_duration.dart b/lib/views/widgets/styled/input_adder/date_duration.dart deleted file mode 100644 index 095a440..0000000 --- a/lib/views/widgets/styled/input_adder/date_duration.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:Organiser/views/widgets/styled/input_adder/date.dart'; -import 'package:Organiser/views/widgets/styled/input_adder/time.dart'; -import 'package:flutter/material.dart'; - -// ignore: must_be_immutable -class DateAndTimeAdder extends StatefulWidget { - final Map dateAndTimeController; - DateTime? dateController; - DateTime? endDateController; - TimeOfDay? startTimeController; - TimeOfDay? endTimeController; - bool isMultiDay = true; - - DateAndTimeAdder({required this.dateAndTimeController}); - - @override - _DateAndTimeAdder createState() => _DateAndTimeAdder(); -} - -class _DateAndTimeAdder extends State{ - - Widget build(BuildContext context) { - return Column( - children: [ - DateAdder( - dateController: widget.dateController, - endDateController: widget.endDateController, - isMultiDayController: widget.isMultiDay, - ), - SizedBox(height: 16.0,), - TimeAdder( - isMultiDay: widget.isMultiDay, - isDuration: true, - startTimeController: widget.startTimeController, - endTimeController: widget.endTimeController, - canBeMultiDay: true, - ), - ], - ); - } - -} diff --git a/lib/views/widgets/styled/input_adder/image.dart b/lib/views/widgets/styled/input_adder/image.dart deleted file mode 100644 index 1fc623d..0000000 --- a/lib/views/widgets/styled/input_adder/image.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:Organiser/views/widgets/input/buttons.dart'; -import 'package:Organiser/views/widgets/input/description.dart'; -import 'package:flutter/material.dart'; - -class ImageAdder extends StatelessWidget { - final String imageUrlController; - - ImageAdder({required this.imageUrlController}); - - // Future _pickImage() async { - // XFile? image = await _imagePicker.pickImage(source: ImageSource.gallery); - // if (image != null) { - // setState(() { - // imageUrlController = image as PickedFile?; - // }); - // } - // } - - @override - Widget build(BuildContext context) { - return StyledButtons.primaryElevatedButton( - onPressed: () { - Navigator.push( - context, - DialogRoute( - context: context, - builder: (context) => DescriptionEditorPage())); - }, - text: 'Image', - icon: Icons.edit_document, - context: context, - verticalPadding: 0, - ); - } -} diff --git a/lib/views/widgets/styled/input_adder/location.dart b/lib/views/widgets/styled/input_adder/location.dart deleted file mode 100644 index 1f705ff..0000000 --- a/lib/views/widgets/styled/input_adder/location.dart +++ /dev/null @@ -1,81 +0,0 @@ -import 'package:Organiser/config/themes/light.dart'; -import 'package:Organiser/views/services/theme_provider.dart'; -import 'package:flutter/material.dart'; -import 'dart:ui' as ui; - -import 'package:provider/provider.dart'; - -// ignore: must_be_immutable -class LocationAdder extends StatelessWidget { - - final Map locationController; - - - LocationAdder({required this.locationController}); - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: () {}, - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(25), - ), - elevation: 0, - margin: EdgeInsets.zero, - child: ClipRRect( - borderRadius: BorderRadius.circular(25), - child: Stack( - alignment: Alignment.center, - children: [ - ImageFiltered( - imageFilter: ui.ImageFilter.blur(sigmaX: 1, sigmaY: 1), - child: Image.asset( Provider.of(context).themeData == lightMode? - 'assets/map.jpg' : 'assets/map_dark.jpg', - fit: BoxFit.cover, - width: double.infinity, - height: 120, - ), - ), - Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Icon( - Icons.location_on, - color: Colors.red, - size: 30, - ), - SizedBox(height: 5), - Column( - children: [ - Text( - 'Select Location', - style: TextStyle( - fontSize: 18, - color: Theme.of(context).colorScheme.primary), - ), - SizedBox( - height: 3, - ), - Text( - 'More description about the specific location', - style: TextStyle( - fontSize: 13, - color: Theme.of(context).hintColor), - ), - ], - ), - ], - ), - ), - ], - ), - ), - ), - ); - } - - void setState(Null Function() param0) {} -} diff --git a/lib/views/widgets/styled/input_adder/note.dart b/lib/views/widgets/styled/input_adder/note.dart deleted file mode 100644 index 0dee1bd..0000000 --- a/lib/views/widgets/styled/input_adder/note.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:Organiser/views/widgets/input/buttons.dart'; -import 'package:Organiser/views/widgets/input/description.dart'; -import 'package:flutter/material.dart'; - -class NotesAdder extends StatelessWidget { - final TextEditingController notesController; - - NotesAdder({required this.notesController}); - - @override - Widget build(BuildContext context) { - return StyledButtons.primaryElevatedButton( - onPressed: () { - Navigator.push( - context, - DialogRoute( - context: context, - builder: (context) => DescriptionEditorPage())); - }, - text: 'Notes', - icon: Icons.edit_document, - context: context, - verticalPadding: 0, - ); - } -} diff --git a/lib/views/widgets/styled/input_adder/repeat.dart b/lib/views/widgets/styled/input_adder/repeat.dart deleted file mode 100644 index c408505..0000000 --- a/lib/views/widgets/styled/input_adder/repeat.dart +++ /dev/null @@ -1,228 +0,0 @@ -import 'package:Organiser/models/common/meal.dart'; -import 'package:flutter/material.dart'; - - -// ignore: must_be_immutable -class RepeatAdderWidget extends StatelessWidget { - final Map repeatController; - final bool repeatOnController; - String selectedChip = ''; - - RepeatAdderWidget({ - required this.repeatController, - required this.repeatOnController, - }); - - @override - Widget build(BuildContext context) { - return Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(25.0), - ), - elevation: 0, - margin: EdgeInsets.symmetric(vertical: 15, horizontal: 0), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 10.0), - child: - Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - GestureDetector( - onTap: () { - _showRepeatFrequencyDialog(context); - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Every Year", - style: TextStyle( - fontSize: 16, - ), - ), - Icon( - Icons.repeat, - size: 25, - color: Theme.of(context).colorScheme.primary, - ), - ], - ), - ), - SizedBox( - height: 15, - ), - Text( - "On: Jan, 15", - style: TextStyle( - fontSize: 24, - color: Theme.of(context).hintColor, - ), - ), - // Text( - // "On the last Wednesday", - // style: TextStyle( - // fontSize: 24, - // color: Theme.of(context).hintColor, - // ), - // ) - // Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // children: [ - // buildSelectableChip('S'), - // buildSelectableChip('M'), - // buildSelectableChip('T'), - // buildSelectableChip('W'), - // buildSelectableChip('T'), - // buildSelectableChip('F'), - // buildSelectableChip('S'), - // ], - // ) - ]), - ), - ); - } - - Widget buildSelectableChip(String label, {double fontSize = 14}) { - return ChoiceChip( - label: Text( - label, - style: TextStyle( - fontSize: fontSize, - fontWeight: FontWeight.w300, - // color: selectedChip == label - // ? Theme.of(context).cardColor - // : Theme.of(context).colorScheme.primary), - ), - // selected: - // selectedColor: Theme.of(context).colorScheme.primary, - // onSelected: (bool selected) { - // setState(() { - // selectedChip = selected ? label : ''; - // }); - // }, - // side: BorderSide(color: Theme.of(context).colorScheme.primary), - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(30.0), - // ), - // backgroundColor: Theme.of(context).colorScheme.primary.withOpacity(0), - ), - selected: selectedChip == label, - ); - } - - void _showRepeatFrequencyDialog(BuildContext context) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - shape: - RoundedRectangleBorder(borderRadius: BorderRadius.circular(50)), - backgroundColor: Theme.of(context).cardColor.withOpacity(0.90), - content: SizedBox( - width: MediaQuery.of(context).size.width * 0.8, - child: IntrinsicHeight( - child: RepeatFrequencyOptions(), - ), - ), - actions: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: Text('Cancel'), - ), - TextButton( - onPressed: () { - // Perform the necessary actions with the selected frequency - Navigator.of(context).pop(); - }, - child: Text('OK'), - ), - ], - ) - ], - ); - }, - ); - } -} - -class RepeatFrequencyOptions extends StatefulWidget { - @override - _RepeatFrequencyOptionsState createState() => _RepeatFrequencyOptionsState(); -} - -class _RepeatFrequencyOptionsState extends State { - String selectedFrequency = 'Daily'; - - @override - Widget build(BuildContext context) { - return Column( - children: [ - RadioListTile( - title: Text("Don't Repeat Event"), - value: "Don't Repeat", - groupValue: selectedFrequency, - onChanged: (value) { - setState(() { - selectedFrequency = value!; - }); - }, - ), - Divider( - height: 1, - ), - RadioListTile( - title: Text('Daily'), - value: 'Daily', - groupValue: selectedFrequency, - onChanged: (value) { - setState(() { - selectedFrequency = value!; - }); - }, - ), - Divider( - height: 1, - ), - RadioListTile( - title: Text('Weekly'), - value: 'Weekly', - groupValue: selectedFrequency, - onChanged: (value) { - setState(() { - selectedFrequency = value!; - }); - }, - ), - Divider( - height: 1, - ), - RadioListTile( - title: Text('Monthly'), - value: 'Monthly', - groupValue: selectedFrequency, - onChanged: (value) { - setState(() { - selectedFrequency = value!; - }); - }, - ), - Divider( - height: 1, - ), - RadioListTile( - title: Text('Yearly'), - value: 'Yearly', - groupValue: selectedFrequency, - onChanged: (value) { - setState(() { - selectedFrequency = value!; - }); - }, - ), - ], - ); - } -} diff --git a/lib/views/widgets/styled/input_adder/tag.dart b/lib/views/widgets/styled/input_adder/tag.dart deleted file mode 100644 index 5b42ac8..0000000 --- a/lib/views/widgets/styled/input_adder/tag.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:Organiser/views/widgets/dialogs/add_tag.dart'; -import 'package:Organiser/views/widgets/input/buttons.dart'; -import 'package:flutter/material.dart'; - -// ignore: must_be_immutable -class TagsAdder extends StatelessWidget { - - List selectedTags = []; - - TagsAdder({required this.selectedTags}); - - @override - Widget build(BuildContext context) { - return StyledButtons.primaryElevatedButton( - onPressed: () async { - List? result = await AddTagDialog.show(context); - setState(() { - selectedTags = result!; - }); - }, - verticalPadding: 0, - text: 'Tags', - icon: Icons.bookmark_add_outlined, - context: context); - } - - void setState(Null Function() param0) {} -} diff --git a/lib/views/widgets/styled/input_adder/ticket.dart b/lib/views/widgets/styled/input_adder/ticket.dart deleted file mode 100644 index 24ed96f..0000000 --- a/lib/views/widgets/styled/input_adder/ticket.dart +++ /dev/null @@ -1,112 +0,0 @@ -import 'package:flutter/material.dart'; - -// ignore: must_be_immutable -class TicketsAdder extends StatefulWidget { - final TextEditingController ticketsController; - final TextEditingController costPerTicketController; - bool setEventTime = true; - bool setEventTickets = true; - - TicketsAdder( - {required this.ticketsController, required this.costPerTicketController}); - - @override - _TicketsAdder createState() => _TicketsAdder(); -} - -class _TicketsAdder extends State { - @override - Widget build(BuildContext context) { - return Column( - children: [ - Padding( - padding: const EdgeInsets.only(right: 10.0, ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SizedBox( - height: 25, - child: ToggleButtons( - children: [ - Text( - 'Tickets', - style: - TextStyle(fontSize: 10, fontWeight: FontWeight.w300), - ), - Text( - 'No Ticket', - style: - TextStyle(fontSize: 10, fontWeight: FontWeight.w300), - ), - ], - isSelected: [widget.setEventTickets, !widget.setEventTickets], - onPressed: (index) { - setState(() { - widget.setEventTickets = index == 0 ? true : false; - }); - }, - borderRadius: BorderRadius.circular(50.0), - ), - ), - Text("Add Tickets", - style: TextStyle( - color: Theme.of(context).hintColor, - fontSize: 14, - decoration: widget.setEventTickets - ? TextDecoration.underline - : TextDecoration.lineThrough, - decorationThickness: 2)), - ], - ), - ), - if (widget.setEventTickets) - SizedBox( - height: 15, - ), - if (widget.setEventTickets) - Row( - children: [ - Expanded( - child: _buildRoundedTextField( - controller: TextEditingController(), - labelText: 'Number of tickets', - myIcon: Icons.calculate_outlined, - context: context, - ), - ), - SizedBox(width: 10), - Expanded( - child: _buildRoundedTextField( - controller: TextEditingController(), - labelText: 'Cost Per Ticket', - myIcon: Icons.attach_money_rounded, - context: context, - ), - ), - ], - ) - ], - ); - } - - Widget _buildRoundedTextField( - {required TextEditingController controller, - required String labelText, - required IconData myIcon, - required BuildContext context}) { - return TextField( - controller: controller, - keyboardType: TextInputType.number, - decoration: InputDecoration( - fillColor: Theme.of(context).colorScheme.secondary.withOpacity(0.5), - filled: true, - labelText: labelText, - labelStyle: TextStyle(fontSize: 13), - suffixIcon: Icon(myIcon), - border: OutlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.circular(10)), - ), - ); - } -} diff --git a/lib/views/widgets/styled/input_adder/time.dart b/lib/views/widgets/styled/input_adder/time.dart deleted file mode 100644 index 01ae716..0000000 --- a/lib/views/widgets/styled/input_adder/time.dart +++ /dev/null @@ -1,194 +0,0 @@ -// ignore_for_file: must_be_immutable -import 'package:Organiser/views/widgets/styled/input_adder/chips.dart'; -import 'package:flutter/material.dart'; - -class TimeAdder extends StatefulWidget { - final TimeOfDay? timeController; - final TimeOfDay? startTimeController; - final TimeOfDay? endTimeController; - final bool isDuration; - bool setTime = true; - bool sameEachDay = true; - - final bool isMultiDay; - final bool canBeMultiDay; - - TimeAdder({ - this.timeController, - this.startTimeController, - this.endTimeController, - required this.isMultiDay, - required this.isDuration, - required this.canBeMultiDay, - }); - - @override - _TimeAdder createState() => _TimeAdder(); -} - -class _TimeAdder extends State { - List selectableChips = List.generate( - 5, // Adjust the number of chips as needed - (index) => SelectableChip( - label: 'Date ${index + 1}', - ), - ); - - @override - Widget build(BuildContext context) { - return Column( - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 5.0, left: 8.0, right: 8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SizedBox( - height: 25, - child: ToggleButtons( - children: [ - Text( - 'Time', - style: - TextStyle(fontSize: 10, fontWeight: FontWeight.w300), - ), - Text( - 'All day', - style: - TextStyle(fontSize: 10, fontWeight: FontWeight.w300), - ), - ], - isSelected: [widget.setTime, !widget.setTime], - onPressed: (index) { - setState(() { - widget.setTime = index == 0 ? true : false; - }); - }, - borderRadius: BorderRadius.circular(50.0), - ), - ), - if (widget.isMultiDay) - Row( - children: [ - Text('Same each day'), - Switch( - value: widget.sameEachDay, - onChanged: (bool newValue) { - setState(() { - widget.sameEachDay = newValue; - }); - }, - ), - ], - ), - ], - ), - ), - SizedBox( - height: 15, - ), - if (widget.setTime) - Card( - margin: EdgeInsets.zero, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(25.0), - ), - elevation: 0, - child: Padding( - padding: - const EdgeInsets.symmetric(vertical: 10.0, horizontal: 5), - child: Column( - children: [ - if (widget.sameEachDay) - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - children: List.generate( - 10, // Adjust the number of chips as needed - (index) => SelectableChip( - label: 'Sat, Mar ${index + 1}', - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 15.0, vertical: 0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "STARTS", - style: TextStyle( - fontSize: 10, fontWeight: FontWeight.w300), - ), - Text( - "ENDS", - style: TextStyle( - fontSize: 10, fontWeight: FontWeight.w300), - ), - ], - ), - ), - SizedBox(height: 10.0), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - '08:00', - style: TextStyle( - fontSize: 40, - color: Theme.of(context).hintColor - ..withOpacity(0.7), - ), - ), - Text( - '16:00', - style: TextStyle( - fontSize: 40, - color: Theme.of(context).hintColor.withOpacity(0.7), - ), - ) - ], - ), - ), - SizedBox(width: 10), - if (widget.sameEachDay) - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - TextButton( - onPressed: onResetClicked, - child: Text('RESET TIME'), - ), - TextButton( - onPressed: onSaveClicked, - child: Text("SAVE DATE'S TIME"), - ), - ], - ), - ], - ), - ), - ), - ], - ); - } - - void onSaveClicked() { - selectableChips.forEach((chip) { - if (chip.isSelected) { - chip.showAvatar = true; - } - }); - } - - void onResetClicked() { - selectableChips.forEach((chip) { - chip.showAvatar = false; - chip.isSelected = false; - }); - } -} diff --git a/lib/views/widgets/styled/input_adder/timezone.dart b/lib/views/widgets/styled/input_adder/timezone.dart deleted file mode 100644 index 53a0e73..0000000 --- a/lib/views/widgets/styled/input_adder/timezone.dart +++ /dev/null @@ -1,51 +0,0 @@ -// ignore_for_file: must_be_immutable -import 'package:flutter/material.dart'; - -class TimezoneAdder extends StatefulWidget { - TextEditingController timezoneConroller = TextEditingController(); - - TimezoneAdder({required this.timezoneConroller}); - - @override - _TimezoneAdder createState() => _TimezoneAdder(); -} - -class _TimezoneAdder extends State { - @override - Widget build(BuildContext context) { - return Card( - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(25.0), - ), - margin: EdgeInsets.zero, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - Icon( - Icons.public, - color: Theme.of(context).colorScheme.primary, - size: 30, - ), - SizedBox( - width: 5, - ), - Expanded( - child: TextField( - // controller: controller, - decoration: InputDecoration( - labelStyle: TextStyle(fontSize: 13), - hintText: 'GMT 800, East Africa Time, Nairobi', - border: OutlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.circular(15)), - ), - ), - ), - ], - ), - ), - ); - } -} diff --git a/lib/views/widgets/styled/input_adder/title.dart b/lib/views/widgets/styled/input_adder/title.dart deleted file mode 100644 index 4154e5c..0000000 --- a/lib/views/widgets/styled/input_adder/title.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:Organiser/views/widgets/input/textfields.dart'; -import 'package:flutter/material.dart'; - -class TitleAdder extends StatelessWidget { - final TextEditingController titleController; - final TextEditingController priorityController; - - TitleAdder({required this.titleController, required this.priorityController}); - - @override - Widget build(BuildContext context) { - return StyledTextField( - controller: titleController, - label: 'Title', - textSize: 25, - trailingIcon: Icons.circle, - iconColor: Colors.green, - ); - } -} diff --git a/pubspec.lock b/pubspec.lock index 47375c9..c8f9135 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -129,6 +129,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + csslib: + dependency: transitive + description: + name: csslib + sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" + url: "https://pub.dev" + source: hosted + version: "1.0.0" cupertino_icons: dependency: "direct main" description: @@ -185,6 +193,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + file_picker: + dependency: "direct main" + description: + name: file_picker + sha256: d1d0ac3966b36dc3e66eeefb40280c17feb87fa2099c6e22e6a1fc959327bd03 + url: "https://pub.dev" + source: hosted + version: "8.0.0+1" file_selector_linux: dependency: transitive description: @@ -328,6 +344,14 @@ packages: description: flutter source: sdk version: "0.0.0" + html: + dependency: transitive + description: + name: html + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" http: dependency: transitive description: @@ -781,6 +805,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + video_player: + dependency: "direct main" + description: + name: video_player + sha256: afc65f4b8bcb2c188f64a591f84fb471f4f2e19fc607c65fd8d2f8fedb3dec23 + url: "https://pub.dev" + source: hosted + version: "2.8.3" + video_player_android: + dependency: transitive + description: + name: video_player_android + sha256: "4dd9b8b86d70d65eecf3dcabfcdfbb9c9115d244d022654aba49a00336d540c2" + url: "https://pub.dev" + source: hosted + version: "2.4.12" + video_player_avfoundation: + dependency: transitive + description: + name: video_player_avfoundation + sha256: "309e3962795e761be010869bae65c0b0e45b5230c5cee1bec72197ca7db040ed" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + video_player_platform_interface: + dependency: transitive + description: + name: video_player_platform_interface + sha256: "236454725fafcacf98f0f39af0d7c7ab2ce84762e3b63f2cbb3ef9a7e0550bc6" + url: "https://pub.dev" + source: hosted + version: "6.2.2" + video_player_web: + dependency: transitive + description: + name: video_player_web + sha256: "34beb3a07d4331a24f7e7b2f75b8e2b103289038e07e65529699a671b6a6e2cb" + url: "https://pub.dev" + source: hosted + version: "2.1.3" web: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 800f921..3e38b4e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -45,6 +45,8 @@ dependencies: dartz: ^0.10.1 firebase_storage: ^11.6.9 fl_chart: ^0.66.2 + file_picker: ^8.0.0+1 + video_player: ^2.8.3 # syncfusion_flutter_calendar: ^24.1.47 dev_dependencies: