diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..737249f --- /dev/null +++ b/.gitignore @@ -0,0 +1,112 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release +macos/Flutter/ephemeral/flutter_export_environment.sh +macos/Flutter/ephemeral/Flutter-Generated.xcconfig +pubspec.lock +macos/Flutter/GeneratedPluginRegistrant.swift +web/favicon.png +web/index.html +web/manifest.json +web/icons/Icon-192.png +web/icons/Icon-512.png +web/icons/Icon-maskable-192.png +web/icons/Icon-maskable-512.png +android/.gitignore +android/build.gradle +android/gradle.properties +android/settings.gradle +android/app/build.gradle +android/app/src/debug/AndroidManifest.xml +android/app/src/main/AndroidManifest.xml +android/app/src/main/kotlin/com/example/flutter_portugal_scheduler/MainActivity.kt +android/app/src/main/res/drawable/launch_background.xml +android/app/src/main/res/drawable-v21/launch_background.xml +android/app/src/main/res/mipmap-hdpi/ic_launcher.png +android/app/src/main/res/mipmap-mdpi/ic_launcher.png +android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +android/app/src/main/res/values/styles.xml +android/app/src/main/res/values-night/styles.xml +android/app/src/profile/AndroidManifest.xml +android/gradle/wrapper/gradle-wrapper.properties +ios/.gitignore +ios/Flutter/AppFrameworkInfo.plist +ios/Flutter/Debug.xcconfig +ios/Flutter/Release.xcconfig +ios/Runner/AppDelegate.swift +ios/Runner/Info.plist +ios/Runner/Runner-Bridging-Header.h +ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png +ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png +ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png +ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png +ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png +ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png +ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png +ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png +ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png +ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png +ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png +ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png +ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png +ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png +ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png +ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png +ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png +ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png +ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +ios/Runner/Base.lproj/LaunchScreen.storyboard +ios/Runner/Base.lproj/Main.storyboard +ios/Runner.xcodeproj/project.pbxproj +ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +ios/Runner.xcworkspace/contents.xcworkspacedata +ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +ios/RunnerTests/RunnerTests.swift diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..e085b60 --- /dev/null +++ b/.metadata @@ -0,0 +1,39 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "2663184aa79047d0a33a14a3b607954f8fdd8730" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 + base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 + - platform: android + create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 + base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 + - platform: ios + create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 + base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 + - platform: macos + create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 + base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 + - platform: web + create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 + base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/README.md b/README.md new file mode 100644 index 0000000..b7a3f88 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# flutter_portugal_scheduler + + +This is the root project used in the workshop of Flutter Portugal, a community-driven initiative aimed at teaching and promoting the use of Flutter for building natively compiled applications for mobile, web, and desktop. + +The project is an ongoing effort to provide a comprehensive learning resource for individuals looking to get started with Flutter. It contains the source files, configurations, and other essential components necessary for building a Flutter application. + +To get started with this project, follow these steps: + +1. Clone the repository to your local machine using your preferred version control system. +2. Navigate to the root directory of the project in your terminal or command prompt. +3. Run the command `flutter create .` to set up the project and generate the necessary files and configurations. + +Note: Running `flutter create .` will overwrite any existing files in the project directory. Make sure to commit any changes you've made to the project before running this command. + +By following these steps, you'll be able to get started with the project and begin exploring the world of Flutter development. \ No newline at end of file diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..f9b3034 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1 @@ +include: package:flutter_lints/flutter.yaml diff --git a/assets/data.json b/assets/data.json new file mode 100644 index 0000000..d8ac495 --- /dev/null +++ b/assets/data.json @@ -0,0 +1,19 @@ +{ + "events": [ + { + "speaker": "John Doe", + "description": "Introduction to Flutter Development", + "time": "2023-10-01T10:00:00Z" + }, + { + "speaker": "Jane Smith", + "description": "Advanced State Management in Flutter", + "time": "2023-10-01T11:30:00Z" + }, + { + "speaker": "Alice Johnson", + "description": "Building Responsive UIs with Flutter", + "time": "2023-10-01T13:00:00Z" + } + ] + } \ No newline at end of file diff --git a/lib/agenda_controller_cubit.dart b/lib/agenda_controller_cubit.dart new file mode 100644 index 0000000..8a23a41 --- /dev/null +++ b/lib/agenda_controller_cubit.dart @@ -0,0 +1,17 @@ +import 'package:bloc/bloc.dart'; +import 'package:flutter_portugal_scheduler/agenda_controller_state.dart'; +import 'package:flutter_portugal_scheduler/data_repository.dart'; + +class AgendaControllerCubit extends Cubit { + final DataRepository _dataRepository; + + AgendaControllerCubit({ + required DataRepository dataRepository, + }) : _dataRepository = dataRepository, + super(AgendaControllerState(events: null)); + + Future loadEvents() async { + final events = await _dataRepository.loadEvents(); + emit(state.copyWith(events: events)); + } +} diff --git a/lib/agenda_controller_state.dart b/lib/agenda_controller_state.dart new file mode 100644 index 0000000..e1f519a --- /dev/null +++ b/lib/agenda_controller_state.dart @@ -0,0 +1,11 @@ +import 'package:dart_mappable/dart_mappable.dart'; +import 'package:flutter_portugal_scheduler/data.dart'; + +part 'agenda_controller_state.mapper.dart'; + +@MappableClass() +final class AgendaControllerState with AgendaControllerStateMappable { + final Events? events; + + AgendaControllerState({required this.events}); +} diff --git a/lib/agenda_controller_state.mapper.dart b/lib/agenda_controller_state.mapper.dart new file mode 100644 index 0000000..b67884c --- /dev/null +++ b/lib/agenda_controller_state.mapper.dart @@ -0,0 +1,123 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'agenda_controller_state.dart'; + +class AgendaControllerStateMapper + extends ClassMapperBase { + AgendaControllerStateMapper._(); + + static AgendaControllerStateMapper? _instance; + static AgendaControllerStateMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = AgendaControllerStateMapper._()); + EventsMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'AgendaControllerState'; + + static Events? _$events(AgendaControllerState v) => v.events; + static const Field _f$events = + Field('events', _$events); + + @override + final MappableFields fields = const { + #events: _f$events, + }; + + static AgendaControllerState _instantiate(DecodingData data) { + return AgendaControllerState(events: data.dec(_f$events)); + } + + @override + final Function instantiate = _instantiate; + + static AgendaControllerState fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static AgendaControllerState fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin AgendaControllerStateMappable { + String toJson() { + return AgendaControllerStateMapper.ensureInitialized() + .encodeJson(this as AgendaControllerState); + } + + Map toMap() { + return AgendaControllerStateMapper.ensureInitialized() + .encodeMap(this as AgendaControllerState); + } + + AgendaControllerStateCopyWith + get copyWith => _AgendaControllerStateCopyWithImpl( + this as AgendaControllerState, $identity, $identity); + @override + String toString() { + return AgendaControllerStateMapper.ensureInitialized() + .stringifyValue(this as AgendaControllerState); + } + + @override + bool operator ==(Object other) { + return AgendaControllerStateMapper.ensureInitialized() + .equalsValue(this as AgendaControllerState, other); + } + + @override + int get hashCode { + return AgendaControllerStateMapper.ensureInitialized() + .hashValue(this as AgendaControllerState); + } +} + +extension AgendaControllerStateValueCopy<$R, $Out> + on ObjectCopyWith<$R, AgendaControllerState, $Out> { + AgendaControllerStateCopyWith<$R, AgendaControllerState, $Out> + get $asAgendaControllerState => + $base.as((v, t, t2) => _AgendaControllerStateCopyWithImpl(v, t, t2)); +} + +abstract class AgendaControllerStateCopyWith< + $R, + $In extends AgendaControllerState, + $Out> implements ClassCopyWith<$R, $In, $Out> { + EventsCopyWith<$R, Events, Events>? get events; + $R call({Events? events}); + AgendaControllerStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t); +} + +class _AgendaControllerStateCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, AgendaControllerState, $Out> + implements AgendaControllerStateCopyWith<$R, AgendaControllerState, $Out> { + _AgendaControllerStateCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + AgendaControllerStateMapper.ensureInitialized(); + @override + EventsCopyWith<$R, Events, Events>? get events => + $value.events?.copyWith.$chain((v) => call(events: v)); + @override + $R call({Object? events = $none}) => + $apply(FieldCopyWithData({if (events != $none) #events: events})); + @override + AgendaControllerState $make(CopyWithData data) => + AgendaControllerState(events: data.get(#events, or: $value.events)); + + @override + AgendaControllerStateCopyWith<$R2, AgendaControllerState, $Out2> + $chain<$R2, $Out2>(Then<$Out2, $R2> t) => + _AgendaControllerStateCopyWithImpl($value, $cast, t); +} diff --git a/lib/agenda_page.dart b/lib/agenda_page.dart new file mode 100644 index 0000000..8df5b2b --- /dev/null +++ b/lib/agenda_page.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_portugal_scheduler/agenda_controller_cubit.dart'; +import 'package:flutter_portugal_scheduler/agenda_controller_state.dart'; + +class AgendaPage extends StatelessWidget { + const AgendaPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Flutter Portugal Agenda'), + ), + body: const AgendaListView(), + ); + } +} + +class AgendaListView extends StatelessWidget { + const AgendaListView({super.key}); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state.events == null) { + return const Center( + child: Text('No events'), + ); + } + return ListView.builder( + itemCount: state.events!.events.length, + itemBuilder: (context, index) { + return ListTile( + title: Text(state.events!.events[index].speaker), + ); + }, + ); + }, + ); + } +} diff --git a/lib/data.dart b/lib/data.dart new file mode 100644 index 0000000..444be38 --- /dev/null +++ b/lib/data.dart @@ -0,0 +1,29 @@ +// This file is "model.dart" +import 'package:dart_mappable/dart_mappable.dart'; + +// Will be generated by dart_mappable +part 'data.mapper.dart'; + +/// Any class that is mapped from JSON must extend `JsonMappable` +/// +/// This requires the `build_runner` package to be run. +/// +@MappableClass() +class Events with EventsMappable { + final List events; + + Events({required this.events}); +} + +@MappableClass() +class Event with EventMappable { + final String speaker; + final String description; + final DateTime time; + + Event({ + required this.speaker, + required this.description, + required this.time, + }); +} diff --git a/lib/data.mapper.dart b/lib/data.mapper.dart new file mode 100644 index 0000000..d2bd824 --- /dev/null +++ b/lib/data.mapper.dart @@ -0,0 +1,217 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'data.dart'; + +class EventsMapper extends ClassMapperBase { + EventsMapper._(); + + static EventsMapper? _instance; + static EventsMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = EventsMapper._()); + EventMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'Events'; + + static List _$events(Events v) => v.events; + static const Field> _f$events = Field('events', _$events); + + @override + final MappableFields fields = const { + #events: _f$events, + }; + + static Events _instantiate(DecodingData data) { + return Events(events: data.dec(_f$events)); + } + + @override + final Function instantiate = _instantiate; + + static Events fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static Events fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin EventsMappable { + String toJson() { + return EventsMapper.ensureInitialized().encodeJson(this as Events); + } + + Map toMap() { + return EventsMapper.ensureInitialized().encodeMap(this as Events); + } + + EventsCopyWith get copyWith => + _EventsCopyWithImpl(this as Events, $identity, $identity); + @override + String toString() { + return EventsMapper.ensureInitialized().stringifyValue(this as Events); + } + + @override + bool operator ==(Object other) { + return EventsMapper.ensureInitialized().equalsValue(this as Events, other); + } + + @override + int get hashCode { + return EventsMapper.ensureInitialized().hashValue(this as Events); + } +} + +extension EventsValueCopy<$R, $Out> on ObjectCopyWith<$R, Events, $Out> { + EventsCopyWith<$R, Events, $Out> get $asEvents => + $base.as((v, t, t2) => _EventsCopyWithImpl(v, t, t2)); +} + +abstract class EventsCopyWith<$R, $In extends Events, $Out> + implements ClassCopyWith<$R, $In, $Out> { + ListCopyWith<$R, Event, EventCopyWith<$R, Event, Event>> get events; + $R call({List? events}); + EventsCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _EventsCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Events, $Out> + implements EventsCopyWith<$R, Events, $Out> { + _EventsCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = EventsMapper.ensureInitialized(); + @override + ListCopyWith<$R, Event, EventCopyWith<$R, Event, Event>> get events => + ListCopyWith($value.events, (v, t) => v.copyWith.$chain(t), + (v) => call(events: v)); + @override + $R call({List? events}) => + $apply(FieldCopyWithData({if (events != null) #events: events})); + @override + Events $make(CopyWithData data) => + Events(events: data.get(#events, or: $value.events)); + + @override + EventsCopyWith<$R2, Events, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => + _EventsCopyWithImpl($value, $cast, t); +} + +class EventMapper extends ClassMapperBase { + EventMapper._(); + + static EventMapper? _instance; + static EventMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = EventMapper._()); + } + return _instance!; + } + + @override + final String id = 'Event'; + + static String _$speaker(Event v) => v.speaker; + static const Field _f$speaker = Field('speaker', _$speaker); + static String _$description(Event v) => v.description; + static const Field _f$description = + Field('description', _$description); + static DateTime _$time(Event v) => v.time; + static const Field _f$time = Field('time', _$time); + + @override + final MappableFields fields = const { + #speaker: _f$speaker, + #description: _f$description, + #time: _f$time, + }; + + static Event _instantiate(DecodingData data) { + return Event( + speaker: data.dec(_f$speaker), + description: data.dec(_f$description), + time: data.dec(_f$time)); + } + + @override + final Function instantiate = _instantiate; + + static Event fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static Event fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin EventMappable { + String toJson() { + return EventMapper.ensureInitialized().encodeJson(this as Event); + } + + Map toMap() { + return EventMapper.ensureInitialized().encodeMap(this as Event); + } + + EventCopyWith get copyWith => + _EventCopyWithImpl(this as Event, $identity, $identity); + @override + String toString() { + return EventMapper.ensureInitialized().stringifyValue(this as Event); + } + + @override + bool operator ==(Object other) { + return EventMapper.ensureInitialized().equalsValue(this as Event, other); + } + + @override + int get hashCode { + return EventMapper.ensureInitialized().hashValue(this as Event); + } +} + +extension EventValueCopy<$R, $Out> on ObjectCopyWith<$R, Event, $Out> { + EventCopyWith<$R, Event, $Out> get $asEvent => + $base.as((v, t, t2) => _EventCopyWithImpl(v, t, t2)); +} + +abstract class EventCopyWith<$R, $In extends Event, $Out> + implements ClassCopyWith<$R, $In, $Out> { + $R call({String? speaker, String? description, DateTime? time}); + EventCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _EventCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Event, $Out> + implements EventCopyWith<$R, Event, $Out> { + _EventCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = EventMapper.ensureInitialized(); + @override + $R call({String? speaker, String? description, DateTime? time}) => + $apply(FieldCopyWithData({ + if (speaker != null) #speaker: speaker, + if (description != null) #description: description, + if (time != null) #time: time + })); + @override + Event $make(CopyWithData data) => Event( + speaker: data.get(#speaker, or: $value.speaker), + description: data.get(#description, or: $value.description), + time: data.get(#time, or: $value.time)); + + @override + EventCopyWith<$R2, Event, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t) => + _EventCopyWithImpl($value, $cast, t); +} diff --git a/lib/data_repository.dart b/lib/data_repository.dart new file mode 100644 index 0000000..292608e --- /dev/null +++ b/lib/data_repository.dart @@ -0,0 +1,17 @@ +import 'package:flutter/services.dart'; +import 'package:flutter_portugal_scheduler/data.dart'; + +class DataRepository { + Future loadEvents() async { + final json = await loadJson(); + final events = EventsMapper.fromJson(json); + return events; + } +} + +// New method to load JSON from a file +Future loadJson() async { + final String response = + await rootBundle.loadString('assets/data.json'); // Load JSON file + return response; // Decode JSON +} diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..cf3d82c --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_portugal_scheduler/agenda_controller_cubit.dart'; +import 'package:flutter_portugal_scheduler/agenda_page.dart'; +import 'package:flutter_portugal_scheduler/data_repository.dart'; + +void main() { + runApp(BlocProvider( + create: (context) => AgendaControllerCubit( + dataRepository: DataRepository(), + ), + child: const MainApp(), + )); +} + +class MainApp extends StatelessWidget { + const MainApp({super.key}); + + @override + Widget build(BuildContext context) { + return const MaterialApp( + home: AgendaPage(), + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..4a610ae --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,25 @@ +name: flutter_portugal_scheduler +description: "A Flutter Portugal Agenda App" +publish_to: 'none' +version: 0.1.0 + +environment: + sdk: ^3.5.3 + +dependencies: + flutter: + sdk: flutter + dart_mappable: ^4.2.2 + flutter_bloc: ^8.1.6 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^4.0.0 + build_runner: ^2.4.13 + dart_mappable_builder: ^4.2.3 + +flutter: + uses-material-design: true + assets: + - assets/data.json