mirror of
https://github.com/Iconica-Development/flutter_timetable.git
synced 2025-05-18 19:43:43 +02:00
Compare commits
25 commits
Author | SHA1 | Date | |
---|---|---|---|
|
79f31f2552 | ||
|
0136f84a10 | ||
|
333c189428 | ||
|
9bac97f831 | ||
|
8b333e7bb7 | ||
|
32b9f9f2c5 | ||
|
f031828067 | ||
|
651ed33cfc | ||
|
93b25c7db6 | ||
|
01a7cfffb1 | ||
|
dc338d4e37 | ||
|
f79ae93962 | ||
|
3d6a78de65 | ||
|
77d5e2fb36 | ||
|
dd88521c9d | ||
|
e05105d452 | ||
|
18f40b115f | ||
|
2d081f8efa | ||
|
7b80839bea | ||
|
528dc5c240 | ||
|
289f1ea25a | ||
|
ae8d135eb4 | ||
|
8f33c14b83 | ||
|
17954a364e | ||
|
8da3ac0585 |
59 changed files with 1144 additions and 936 deletions
23
.github/dependabot.yml
vendored
Normal file
23
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
version: 2
|
||||
|
||||
updates:
|
||||
# - package-ecosystem: "pub"
|
||||
# directory: "/packages/flutter_timetable"
|
||||
# schedule:
|
||||
# interval: "weekly"
|
||||
|
||||
- package-ecosystem: "pub"
|
||||
directory: "/packages/flutter_timetable_interface"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "pub"
|
||||
directory: "/packages/flutter_timetable_firebase"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "pub"
|
||||
directory: "/packages/flutter_timetable_view"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
14
.github/workflows/component-documentation.yml
vendored
Normal file
14
.github/workflows/component-documentation.yml
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
name: Iconica Standard Component Documentation Workflow
|
||||
# Workflow Caller version: 1.0.0
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
call-iconica-component-documentation-workflow:
|
||||
uses: Iconica-Development/.github/.github/workflows/component-documentation.yml@master
|
||||
secrets: inherit
|
||||
permissions: write-all
|
14
.github/workflows/melos-ci.yml
vendored
Normal file
14
.github/workflows/melos-ci.yml
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
name: Iconica Standard Melos CI Workflow
|
||||
# Workflow Caller version: 1.0.0
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
call-global-iconica-workflow:
|
||||
uses: Iconica-Development/.github/.github/workflows/melos-ci.yml@master
|
||||
secrets: inherit
|
||||
permissions: write-all
|
||||
with:
|
||||
subfolder: '.' # add optional subfolder to run workflow in
|
20
.github/workflows/release.yml
vendored
Normal file
20
.github/workflows/release.yml
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
name: Component Release Documentation Update
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- created
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
trigger:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Trigger central repository workflow
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/Iconica-Development/iconica_component_documentation/actions/workflows/documentation.yml/dispatches \
|
||||
-d '{"ref":"master", "inputs":{"repository_url":"${{ github.event.repository.html_url }}"}}'
|
20
.gitignore
vendored
20
.gitignore
vendored
|
@ -23,15 +23,31 @@ migrate_working_dir/
|
|||
|
||||
# Flutter/Dart/Pub related
|
||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||
/pubspec.lock
|
||||
pubspec.lock
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
.packages
|
||||
build/
|
||||
.metadata
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
|
||||
android/
|
||||
ios/
|
||||
web/
|
||||
linux/
|
||||
macos/
|
||||
windows/
|
||||
|
||||
pubspec_overrides.yaml
|
||||
|
||||
example/android/
|
||||
example/ios/
|
||||
example/web/
|
||||
example/linux/
|
||||
example/macos/
|
||||
example/windows/
|
||||
example/windows/
|
||||
|
||||
# FVM Version Cache
|
||||
.fvm/
|
||||
.fvmrc
|
||||
|
|
10
.metadata
10
.metadata
|
@ -1,10 +0,0 @@
|
|||
# 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: f1875d570e39de09040c8f79aa13cc56baab8db1
|
||||
channel: stable
|
||||
|
||||
project_type: package
|
30
CHANGELOG.md
30
CHANGELOG.md
|
@ -10,3 +10,33 @@
|
|||
|
||||
* Added horizontal variant
|
||||
* Adjustable size for the component
|
||||
|
||||
## [1.1.0] - 17 August 2023
|
||||
|
||||
* Set scrolling to the current time by default if there are no blocks
|
||||
|
||||
## [1.2.0] - 6 November 2023
|
||||
|
||||
* Add the ability to use BorderScroll. If enabled the next page is shown when scrolling to an specific offset.
|
||||
|
||||
## [1.2.1] - 7 November 2023
|
||||
|
||||
* Fixed the assert on the [scrollTriggerOffset] and [scrollJumpToOffset].
|
||||
|
||||
## [1.3.0] - 8 November 2023
|
||||
|
||||
* Add the option for setting an offset for the hours so that the first hour is not 00:00 but 08:00 for example and the last hour can be after 24:00.
|
||||
|
||||
## [1.4.0] - 13 November 2023
|
||||
|
||||
* Add the option for sorting the blocks by their id.
|
||||
|
||||
## [2.0.0] - 03 December 2023
|
||||
|
||||
* Create Melos variant of the component where there are multiple packages in the same repository.
|
||||
|
||||
* Added the option to sort on the starttime of an event.
|
||||
|
||||
## [3.0.0] - 11 July 2024
|
||||
|
||||
* Rename main entry point to flutter_timetable
|
||||
|
|
198
CONTRIBUTING.md
Normal file
198
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,198 @@
|
|||
# Contributing
|
||||
|
||||
First off, thanks for taking the time to contribute! ❤️
|
||||
|
||||
All types of contributions are encouraged and valued.
|
||||
See the [Table of Contents](#table-of-contents) for different ways to help and details about how we handle them.
|
||||
Please make sure to read the relevant section before making your contribution.
|
||||
It will make it a lot easier for us maintainers and smooth out the experience for all involved.
|
||||
Iconica looks forward to your contributions. 🎉
|
||||
|
||||
## Table of contents
|
||||
|
||||
- [Code of conduct](#code-of-conduct)
|
||||
- [I Have a Question](#i-have-a-question)
|
||||
- [I Want To Contribute](#i-want-to-contribute)
|
||||
- [Reporting Bugs](#reporting-bugs)
|
||||
- [Contributing code](#contributing-code)
|
||||
|
||||
## Code of conduct
|
||||
|
||||
### Legal notice
|
||||
|
||||
When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license.
|
||||
All accepted pull requests and other additions to this project will be considered intellectual property of Iconica.
|
||||
|
||||
All repositories should be kept clean of jokes, easter eggs and other unnecessary additions.
|
||||
|
||||
## I have a question
|
||||
|
||||
If you want to ask a question, we assume that you have read the available documentation found within the code.
|
||||
Before you ask a question, it is best to search for existing issues that might help you.
|
||||
In case you have found a suitable issue but still need clarification, you can ask your question
|
||||
It is also advisable to search the internet for answers first.
|
||||
|
||||
If you then still feel the need to ask a question and need clarification, we recommend the following:
|
||||
|
||||
- Open an issue.
|
||||
- Provide as much context as you can about what you're running into.
|
||||
|
||||
We will then take care of the issue as soon as possible.
|
||||
|
||||
## I want to contribute
|
||||
|
||||
### Reporting bugs
|
||||
|
||||
<!-- omit in toc -->
|
||||
|
||||
**Before submitting a bug report**
|
||||
|
||||
A good bug report shouldn't leave others needing to chase you up for more information.
|
||||
Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report.
|
||||
Please complete the following steps in advance to help us fix any potential bug as fast as possible.
|
||||
|
||||
- Make sure that you are using the latest version.
|
||||
- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (If you are looking for support, you might want to check [this section](#i-have-a-question)).
|
||||
- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error.
|
||||
- Also make sure to search the internet (including Stack Overflow) to see if users outside of Iconica have discussed the issue.
|
||||
- Collect information about the bug:
|
||||
- Stack trace (Traceback)
|
||||
- OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
|
||||
- Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
|
||||
- Time and date of occurance
|
||||
- Describe the expected result and actual result
|
||||
- Can you reliably reproduce the issue? And can you also reproduce it with older versions? Describe all steps that lead to the bug.
|
||||
|
||||
Once it's filed:
|
||||
|
||||
- The project team will label the issue accordingly.
|
||||
- A team member will try to reproduce the issue with your provided steps.
|
||||
If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for additional information.
|
||||
- If the team is able to reproduce the issue, it will be moved into the backlog, as well as marked with a priority, and the issue will be left to be [implemented by someone](#contributing-code).
|
||||
|
||||
### Contributing code
|
||||
|
||||
When you start working on your contribution, make sure you are aware of the relevant documentation and the functionality of the component you are working on.
|
||||
|
||||
When writing code, follow the style guidelines set by Dart: [Effective Dart](https://Dart.dev/guides/language/effective-Dart). This contains most information you will need to write clean Dart code that is well documented.
|
||||
|
||||
**Documentation**
|
||||
|
||||
As Effective Dart indicates, documenting your public methods with Dart doc comments is recommended.
|
||||
Aside from Effective Dart, we require specific information in the documentation of a method:
|
||||
|
||||
At the very least, your documentation should first name what the code does, then followed below by requirements for calling the method, the result of the method.
|
||||
Any references to internal variables or other methods should be done through [var] to indicate a reference.
|
||||
|
||||
If the method or class is complex enough (determined by the reviewers) an example is required.
|
||||
If unsure, add an example in the docs using code blocks.
|
||||
|
||||
For classes and methods, document the individual parameters with their implications.
|
||||
|
||||
> Tip: Remember that the shortest documentation can be written by having good descriptive names in the first place.
|
||||
|
||||
An example:
|
||||
|
||||
````Dart
|
||||
library iconica_utilities.bidirectional_sorter;
|
||||
|
||||
part 'sorter.Dart';
|
||||
part 'enum.Dart';
|
||||
|
||||
/// Generic sort method, allow sorting of list with primitives or complex types.
|
||||
/// Uses [SortDirection] to determine the direction, either Ascending or Descending,
|
||||
/// Gets called on [List] toSort of type [T] which cannot be shorter than 2.
|
||||
/// Optionally for complex types a [Comparable] [Function] can be given to compare complex types.
|
||||
/// ```
|
||||
/// List<TestObject> objects = [];
|
||||
/// for (int i = 0; i < 10; i++) {
|
||||
/// objects.add(TestObject(name: "name", id: i));
|
||||
/// }
|
||||
///
|
||||
/// sort<TestObject>(
|
||||
/// SortDirection.descending, objects, (object) => object.id);
|
||||
///
|
||||
/// ```
|
||||
/// In the above example a list of TestObjects is created, and then sorted in descending order.
|
||||
/// If the implementation of TestObject is as following:
|
||||
/// ```
|
||||
/// class TestObject {
|
||||
/// final String name;
|
||||
/// final int id;
|
||||
///
|
||||
/// TestObject({required this.name, required this.id});
|
||||
/// }
|
||||
/// ```
|
||||
/// And the list is logged to the console, the following will appear:
|
||||
/// ```
|
||||
/// [name9, name8, name7, name6, name5, name4, name3, name2, name1, name0]
|
||||
/// ```
|
||||
|
||||
void sort<T>(
|
||||
/// Determines the sorting direction, can be either Ascending or Descending
|
||||
SortDirection sortDirection,
|
||||
|
||||
/// Incoming list, which gets sorted
|
||||
List<T> toSort, [
|
||||
|
||||
/// Optional comparable, which is only necessary for complex types
|
||||
SortFieldGetter<T>? sortValueCallback,
|
||||
]) {
|
||||
if (toSort.length < 2) return;
|
||||
assert(
|
||||
toSort.whereType<Comparable>().isNotEmpty || sortValueCallback != null);
|
||||
BidirectionalSorter<T>(
|
||||
sortInstructions: <SortInstruction<T>>[
|
||||
SortInstruction(
|
||||
sortValueCallback ?? (t) => t as Comparable, sortDirection),
|
||||
],
|
||||
).sort(toSort);
|
||||
}
|
||||
|
||||
/// same functionality as [sort] but with the added functionality
|
||||
/// of sorting multiple values
|
||||
void sortMulti<T>(
|
||||
/// Incoming list, which gets sorted
|
||||
List<T> toSort,
|
||||
|
||||
/// list of comparables to sort multiple values at once,
|
||||
/// priority based on index
|
||||
List<SortInstruction<T>> sortValueCallbacks,
|
||||
) {
|
||||
if (toSort.length < 2) return;
|
||||
assert(sortValueCallbacks.isNotEmpty);
|
||||
BidirectionalSorter<T>(
|
||||
sortInstructions: sortValueCallbacks,
|
||||
).sort(toSort);
|
||||
}
|
||||
|
||||
````
|
||||
|
||||
**Tests**
|
||||
|
||||
For each public method that was created, excluding widgets, which contains any form of logic (e.g. Calculations, predicates or major side-effects) tests are required.
|
||||
|
||||
A set of tests is written for each method, covering at least each path within the method. For example:
|
||||
|
||||
```Dart
|
||||
void foo() {
|
||||
try {
|
||||
var bar = doSomething();
|
||||
if (bar) {
|
||||
doSomethingElse();
|
||||
} else {
|
||||
doSomethingCool();
|
||||
}
|
||||
} catch (_) {
|
||||
displayError();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The method above should result in 3 tests:
|
||||
|
||||
1. A test for the path leading to displayError by the cause of an exception
|
||||
2. A test for if bar is true, resulting in doSomethingElse()
|
||||
3. A test for if bar is false, resulting in the doSomethingCool() method being called.
|
||||
|
||||
This means that we require 100% coverage of each method you test.
|
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2022 Iconica, All rights reserved.
|
||||
Copyright (c) 2023 Iconica, All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
|
|
27
README.md
27
README.md
|
@ -1,24 +1,27 @@
|
|||
|
||||
# timetable
|
||||
A Flutter package for creating a timetable widget in which to display blocks of time with optional widgets in them.
|
||||
[](https://github.com/Iconica-Development) [](https://github.com/Iconica-Development/flutter_timetable/actions/new) [](https://github.com/tenhobi/effective_dart)
|
||||
# Flutter Timetable
|
||||
A Flutter package for creating a Timetable widget in which to display blocks of time with optional widgets in them.
|
||||
The vertical time range is configurable and the widget is horizontally scrollable. The timetable has options to merge blocks below eachother when they are not overlapping or collapse items that are at the same time and have the same identifier.
|
||||
|
||||
Supports all Flutter platforms.
|
||||

|
||||
|
||||
## Usage
|
||||
## Features
|
||||
## Setup
|
||||
|
||||
To use this package, add `timetable` as a [dependency in your pubspec.yaml file](https://flutter.dev/docs/development/platform-integration/platform-channels).
|
||||
To use this package, add `timetable` as a dependency in your pubspec.yaml file.
|
||||
|
||||
### Example
|
||||
|
||||
See [Example Code](example/lib/main.dart) for more info.
|
||||
|
||||
### Issues & Feedback
|
||||
## Issues
|
||||
|
||||
Please file an [issue](https://github.com/Iconica-Development/timetable/issues) to send feedback or report a bug,
|
||||
If you want to ask a question or suggest an idea then you can [open an discussion](https://github.com/Iconica-Development/timetable/discussions).
|
||||
Thank you!
|
||||
Please file any issues, bugs or feature request as an issue on our [GitHub](https://github.com/Iconica-Development/flutter_date_time_picker/pulls) page. Commercial support is available if you need help with integration with your app or services. You can contact us at [support@iconica.nl](mailto:support@iconica.nl).
|
||||
|
||||
### Contributing
|
||||
## Want to contribute
|
||||
|
||||
Every pull request is welcome.
|
||||
If you would like to contribute to the plugin (e.g. by improving the documentation, solving a bug or adding a cool new feature), please carefully review our [contribution guide](./CONTRIBUTING.md) and send us your [pull request](https://github.com/Iconica-Development/flutter_date_time_picker/pulls).
|
||||
|
||||
## Author
|
||||
|
||||
This `timetable` for Flutter is developed by [Iconica](https://iconica.nl). You can contact us at <support@iconica.nl>
|
|
@ -1,214 +0,0 @@
|
|||
include: package:flutter_lints/flutter.yaml
|
||||
analyzer:
|
||||
errors:
|
||||
todo: ignore
|
||||
exclude: [lib/generated_plugin_registrant.dart]
|
||||
linter:
|
||||
# https://dart.dev/tools/linter-rules#lints
|
||||
rules:
|
||||
# error rules
|
||||
always_use_package_imports: false
|
||||
avoid_dynamic_calls: true
|
||||
avoid_empty_else: true
|
||||
avoid_print: true
|
||||
avoid_relative_lib_imports: true
|
||||
avoid_returning_null_for_future: true
|
||||
avoid_slow_async_io: true
|
||||
avoid_type_to_string: true
|
||||
avoid_types_as_parameter_names: true
|
||||
avoid_web_libraries_in_flutter: true
|
||||
cancel_subscriptions: true
|
||||
close_sinks: true
|
||||
comment_references: false
|
||||
control_flow_in_finally: true
|
||||
diagnostic_describe_all_properties: false
|
||||
empty_statements: true
|
||||
hash_and_equals: true
|
||||
invariant_booleans: true
|
||||
iterable_contains_unrelated_type: true
|
||||
list_remove_unrelated_type: true
|
||||
literal_only_boolean_expressions: true
|
||||
no_adjacent_strings_in_list: true
|
||||
no_duplicate_case_values: true
|
||||
no_logic_in_create_state: true
|
||||
prefer_relative_imports: false
|
||||
prefer_void_to_null: true
|
||||
test_types_in_equals: true
|
||||
throw_in_finally: true
|
||||
unnecessary_statements: true
|
||||
unrelated_type_equality_checks: true
|
||||
unsafe_html: true
|
||||
use_build_context_synchronously: true
|
||||
use_key_in_widget_constructors: true
|
||||
valid_regexps: true
|
||||
# style rules
|
||||
always_declare_return_types: true
|
||||
always_put_control_body_on_new_line: true
|
||||
always_put_required_named_parameters_first: true
|
||||
always_require_non_null_named_parameters: true
|
||||
always_specify_types: false
|
||||
annotate_overrides: true
|
||||
avoid_annotating_with_dynamic: false
|
||||
avoid_bool_literals_in_conditional_expressions: true
|
||||
avoid_catches_without_on_clauses: false
|
||||
avoid_catching_errors: false
|
||||
avoid_classes_with_only_static_members: true
|
||||
avoid_double_and_int_checks: true
|
||||
avoid_equals_and_hash_code_on_mutable_classes: false
|
||||
avoid_escaping_inner_quotes: false
|
||||
avoid_field_initializers_in_const_classes: true
|
||||
avoid_final_parameters: true
|
||||
avoid_function_literals_in_foreach_calls: true
|
||||
avoid_implementing_value_types: true
|
||||
avoid_init_to_null: true
|
||||
avoid_js_rounded_ints: true
|
||||
avoid_multiple_declarations_per_line: true
|
||||
avoid_null_checks_in_equality_operators: true
|
||||
avoid_positional_boolean_parameters: true
|
||||
avoid_private_typedef_functions: true
|
||||
avoid_redundant_argument_values: false
|
||||
avoid_renaming_method_parameters: true
|
||||
avoid_return_types_on_setters: true
|
||||
avoid_returning_null: true
|
||||
avoid_returning_null_for_void: true
|
||||
avoid_returning_this: true
|
||||
avoid_setters_without_getters: true
|
||||
avoid_shadowing_type_parameters: true
|
||||
avoid_single_cascade_in_expression_statements: true
|
||||
avoid_types_on_closure_parameters: false
|
||||
avoid_unnecessary_containers: false
|
||||
avoid_unused_constructor_parameters: true
|
||||
avoid_void_async: true
|
||||
await_only_futures: true
|
||||
camel_case_extensions: true
|
||||
camel_case_types: true
|
||||
cascade_invocations: true
|
||||
cast_nullable_to_non_nullable: true
|
||||
conditional_uri_does_not_exist: true
|
||||
constant_identifier_names: true
|
||||
curly_braces_in_flow_control_structures: true
|
||||
deprecated_consistency: true
|
||||
directives_ordering: true
|
||||
do_not_use_environment: true
|
||||
empty_catches: true
|
||||
empty_constructor_bodies: true
|
||||
eol_at_end_of_file: true
|
||||
exhaustive_cases: true
|
||||
file_names: true
|
||||
flutter_style_todos: true
|
||||
implementation_imports: true
|
||||
join_return_with_assignment: true
|
||||
leading_newlines_in_multiline_strings: true
|
||||
library_names: true
|
||||
library_prefixes: true
|
||||
library_private_types_in_public_api: true
|
||||
lines_longer_than_80_chars: true
|
||||
missing_whitespace_between_adjacent_strings: true
|
||||
no_default_cases: true
|
||||
no_leading_underscores_for_library_prefixes: true
|
||||
no_leading_underscores_for_local_identifiers: true
|
||||
no_runtimeType_toString: true
|
||||
non_constant_identifier_names: true
|
||||
noop_primitive_operations: true
|
||||
null_check_on_nullable_type_parameter: true
|
||||
null_closures: true
|
||||
omit_local_variable_types: true
|
||||
one_member_abstracts: true
|
||||
only_throw_errors: true
|
||||
overridden_fields: true
|
||||
package_api_docs: true
|
||||
package_prefixed_library_names: true
|
||||
parameter_assignments: true
|
||||
prefer_adjacent_string_concatenation: true
|
||||
prefer_asserts_in_initializer_lists: true
|
||||
prefer_asserts_with_message: true
|
||||
prefer_collection_literals: true
|
||||
prefer_conditional_assignment: true
|
||||
prefer_const_constructors: true
|
||||
prefer_const_constructors_in_immutables: true
|
||||
prefer_const_declarations: false
|
||||
prefer_const_literals_to_create_immutables: false
|
||||
prefer_constructors_over_static_methods: true
|
||||
prefer_contains: true
|
||||
prefer_double_quotes: false
|
||||
prefer_equal_for_default_values: true
|
||||
prefer_expression_function_bodies: false
|
||||
prefer_final_fields: true
|
||||
prefer_final_in_for_each: false
|
||||
prefer_final_locals: false
|
||||
prefer_final_parameters: false
|
||||
prefer_for_elements_to_map_fromIterable: true
|
||||
prefer_foreach: true
|
||||
prefer_function_declarations_over_variables: true
|
||||
prefer_generic_function_type_aliases: true
|
||||
prefer_if_elements_to_conditional_expressions: true
|
||||
prefer_if_null_operators: true
|
||||
prefer_initializing_formals: true
|
||||
prefer_inlined_adds: true
|
||||
prefer_int_literals: false
|
||||
prefer_interpolation_to_compose_strings: true
|
||||
prefer_is_empty: true
|
||||
prefer_is_not_empty: true
|
||||
prefer_is_not_operator: true
|
||||
prefer_iterable_whereType: true
|
||||
prefer_mixin: true
|
||||
prefer_null_aware_method_calls: true
|
||||
prefer_null_aware_operators: true
|
||||
prefer_single_quotes: true
|
||||
prefer_spread_collections: true
|
||||
prefer_typing_uninitialized_variables: true
|
||||
provide_deprecation_message: true
|
||||
public_member_api_docs: false
|
||||
recursive_getters: true
|
||||
require_trailing_commas: true
|
||||
sized_box_for_whitespace: true
|
||||
sized_box_shrink_expand: true
|
||||
slash_for_doc_comments: true
|
||||
sort_child_properties_last: true
|
||||
sort_constructors_first: true
|
||||
sort_unnamed_constructors_first: true
|
||||
tighten_type_of_initializing_formals: true
|
||||
type_annotate_public_apis: true
|
||||
type_init_formals: true
|
||||
unawaited_futures: true
|
||||
unnecessary_await_in_return: true
|
||||
unnecessary_brace_in_string_interps: true
|
||||
unnecessary_const: false
|
||||
unnecessary_constructor_name: true
|
||||
unnecessary_final: true
|
||||
unnecessary_getters_setters: true
|
||||
unnecessary_lambdas: true
|
||||
unnecessary_late: true
|
||||
unnecessary_new: true
|
||||
unnecessary_null_aware_assignments: true
|
||||
unnecessary_null_checks: true
|
||||
unnecessary_null_in_if_null_operators: true
|
||||
unnecessary_nullable_for_final_variable_declarations: true
|
||||
unnecessary_overrides: true
|
||||
unnecessary_parenthesis: true
|
||||
unnecessary_raw_strings: true
|
||||
unnecessary_string_escapes: true
|
||||
unnecessary_string_interpolations: true
|
||||
unnecessary_this: true
|
||||
use_decorated_box: true
|
||||
use_full_hex_values_for_flutter_colors: true
|
||||
use_function_type_syntax_for_parameters: true
|
||||
use_if_null_to_convert_nulls_to_bools: true
|
||||
use_is_even_rather_than_modulo: true
|
||||
use_late_for_private_fields_and_variables: true
|
||||
use_named_constants: true
|
||||
use_raw_strings: false
|
||||
use_rethrow_when_possible: true
|
||||
use_setters_to_change_properties: true
|
||||
use_string_buffers: true
|
||||
use_test_throws_matchers: true
|
||||
use_to_and_as_if_applicable: true
|
||||
void_checks: true
|
||||
# pub rules
|
||||
depend_on_referenced_packages: true
|
||||
lowercase_with_underscores: true
|
||||
secure_pubspec_urls: false
|
||||
sort_pub_dependencies: false
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
|
@ -1,45 +0,0 @@
|
|||
# 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.
|
||||
|
||||
version:
|
||||
revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
channel: stable
|
||||
|
||||
project_type: app
|
||||
|
||||
# Tracks metadata for the flutter migrate command
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
- platform: android
|
||||
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
- platform: ios
|
||||
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
- platform: linux
|
||||
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
- platform: macos
|
||||
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
- platform: web
|
||||
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
- platform: windows
|
||||
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
|
||||
# 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'
|
|
@ -1,214 +0,0 @@
|
|||
include: package:flutter_lints/flutter.yaml
|
||||
analyzer:
|
||||
errors:
|
||||
todo: ignore
|
||||
exclude: [lib/generated_plugin_registrant.dart]
|
||||
linter:
|
||||
# https://dart.dev/tools/linter-rules#lints
|
||||
rules:
|
||||
# error rules
|
||||
always_use_package_imports: false
|
||||
avoid_dynamic_calls: true
|
||||
avoid_empty_else: true
|
||||
avoid_print: true
|
||||
avoid_relative_lib_imports: true
|
||||
avoid_returning_null_for_future: true
|
||||
avoid_slow_async_io: true
|
||||
avoid_type_to_string: true
|
||||
avoid_types_as_parameter_names: true
|
||||
avoid_web_libraries_in_flutter: true
|
||||
cancel_subscriptions: true
|
||||
close_sinks: true
|
||||
comment_references: false
|
||||
control_flow_in_finally: true
|
||||
diagnostic_describe_all_properties: false
|
||||
empty_statements: true
|
||||
hash_and_equals: true
|
||||
invariant_booleans: true
|
||||
iterable_contains_unrelated_type: true
|
||||
list_remove_unrelated_type: true
|
||||
literal_only_boolean_expressions: true
|
||||
no_adjacent_strings_in_list: true
|
||||
no_duplicate_case_values: true
|
||||
no_logic_in_create_state: true
|
||||
prefer_relative_imports: false
|
||||
prefer_void_to_null: true
|
||||
test_types_in_equals: true
|
||||
throw_in_finally: true
|
||||
unnecessary_statements: true
|
||||
unrelated_type_equality_checks: true
|
||||
unsafe_html: true
|
||||
use_build_context_synchronously: true
|
||||
use_key_in_widget_constructors: true
|
||||
valid_regexps: true
|
||||
# style rules
|
||||
always_declare_return_types: true
|
||||
always_put_control_body_on_new_line: true
|
||||
always_put_required_named_parameters_first: true
|
||||
always_require_non_null_named_parameters: true
|
||||
always_specify_types: false
|
||||
annotate_overrides: true
|
||||
avoid_annotating_with_dynamic: false
|
||||
avoid_bool_literals_in_conditional_expressions: true
|
||||
avoid_catches_without_on_clauses: false
|
||||
avoid_catching_errors: false
|
||||
avoid_classes_with_only_static_members: true
|
||||
avoid_double_and_int_checks: true
|
||||
avoid_equals_and_hash_code_on_mutable_classes: false
|
||||
avoid_escaping_inner_quotes: false
|
||||
avoid_field_initializers_in_const_classes: true
|
||||
avoid_final_parameters: true
|
||||
avoid_function_literals_in_foreach_calls: true
|
||||
avoid_implementing_value_types: true
|
||||
avoid_init_to_null: true
|
||||
avoid_js_rounded_ints: true
|
||||
avoid_multiple_declarations_per_line: true
|
||||
avoid_null_checks_in_equality_operators: true
|
||||
avoid_positional_boolean_parameters: true
|
||||
avoid_private_typedef_functions: true
|
||||
avoid_redundant_argument_values: false
|
||||
avoid_renaming_method_parameters: true
|
||||
avoid_return_types_on_setters: true
|
||||
avoid_returning_null: true
|
||||
avoid_returning_null_for_void: true
|
||||
avoid_returning_this: true
|
||||
avoid_setters_without_getters: true
|
||||
avoid_shadowing_type_parameters: true
|
||||
avoid_single_cascade_in_expression_statements: true
|
||||
avoid_types_on_closure_parameters: false
|
||||
avoid_unnecessary_containers: false
|
||||
avoid_unused_constructor_parameters: true
|
||||
avoid_void_async: true
|
||||
await_only_futures: true
|
||||
camel_case_extensions: true
|
||||
camel_case_types: true
|
||||
cascade_invocations: true
|
||||
cast_nullable_to_non_nullable: true
|
||||
conditional_uri_does_not_exist: true
|
||||
constant_identifier_names: true
|
||||
curly_braces_in_flow_control_structures: true
|
||||
deprecated_consistency: true
|
||||
directives_ordering: true
|
||||
do_not_use_environment: true
|
||||
empty_catches: true
|
||||
empty_constructor_bodies: true
|
||||
eol_at_end_of_file: true
|
||||
exhaustive_cases: true
|
||||
file_names: true
|
||||
flutter_style_todos: true
|
||||
implementation_imports: true
|
||||
join_return_with_assignment: true
|
||||
leading_newlines_in_multiline_strings: true
|
||||
library_names: true
|
||||
library_prefixes: true
|
||||
library_private_types_in_public_api: true
|
||||
lines_longer_than_80_chars: true
|
||||
missing_whitespace_between_adjacent_strings: true
|
||||
no_default_cases: true
|
||||
no_leading_underscores_for_library_prefixes: true
|
||||
no_leading_underscores_for_local_identifiers: true
|
||||
no_runtimeType_toString: true
|
||||
non_constant_identifier_names: true
|
||||
noop_primitive_operations: true
|
||||
null_check_on_nullable_type_parameter: true
|
||||
null_closures: true
|
||||
omit_local_variable_types: true
|
||||
one_member_abstracts: true
|
||||
only_throw_errors: true
|
||||
overridden_fields: true
|
||||
package_api_docs: true
|
||||
package_prefixed_library_names: true
|
||||
parameter_assignments: true
|
||||
prefer_adjacent_string_concatenation: true
|
||||
prefer_asserts_in_initializer_lists: true
|
||||
prefer_asserts_with_message: true
|
||||
prefer_collection_literals: true
|
||||
prefer_conditional_assignment: true
|
||||
prefer_const_constructors: true
|
||||
prefer_const_constructors_in_immutables: true
|
||||
prefer_const_declarations: false
|
||||
prefer_const_literals_to_create_immutables: false
|
||||
prefer_constructors_over_static_methods: true
|
||||
prefer_contains: true
|
||||
prefer_double_quotes: false
|
||||
prefer_equal_for_default_values: true
|
||||
prefer_expression_function_bodies: false
|
||||
prefer_final_fields: true
|
||||
prefer_final_in_for_each: false
|
||||
prefer_final_locals: false
|
||||
prefer_final_parameters: false
|
||||
prefer_for_elements_to_map_fromIterable: true
|
||||
prefer_foreach: true
|
||||
prefer_function_declarations_over_variables: true
|
||||
prefer_generic_function_type_aliases: true
|
||||
prefer_if_elements_to_conditional_expressions: true
|
||||
prefer_if_null_operators: true
|
||||
prefer_initializing_formals: true
|
||||
prefer_inlined_adds: true
|
||||
prefer_int_literals: false
|
||||
prefer_interpolation_to_compose_strings: true
|
||||
prefer_is_empty: true
|
||||
prefer_is_not_empty: true
|
||||
prefer_is_not_operator: true
|
||||
prefer_iterable_whereType: true
|
||||
prefer_mixin: true
|
||||
prefer_null_aware_method_calls: true
|
||||
prefer_null_aware_operators: true
|
||||
prefer_single_quotes: true
|
||||
prefer_spread_collections: true
|
||||
prefer_typing_uninitialized_variables: true
|
||||
provide_deprecation_message: true
|
||||
public_member_api_docs: false
|
||||
recursive_getters: true
|
||||
require_trailing_commas: true
|
||||
sized_box_for_whitespace: true
|
||||
sized_box_shrink_expand: true
|
||||
slash_for_doc_comments: true
|
||||
sort_child_properties_last: true
|
||||
sort_constructors_first: true
|
||||
sort_unnamed_constructors_first: true
|
||||
tighten_type_of_initializing_formals: true
|
||||
type_annotate_public_apis: true
|
||||
type_init_formals: true
|
||||
unawaited_futures: true
|
||||
unnecessary_await_in_return: true
|
||||
unnecessary_brace_in_string_interps: true
|
||||
unnecessary_const: false
|
||||
unnecessary_constructor_name: true
|
||||
unnecessary_final: true
|
||||
unnecessary_getters_setters: true
|
||||
unnecessary_lambdas: true
|
||||
unnecessary_late: true
|
||||
unnecessary_new: true
|
||||
unnecessary_null_aware_assignments: true
|
||||
unnecessary_null_checks: true
|
||||
unnecessary_null_in_if_null_operators: true
|
||||
unnecessary_nullable_for_final_variable_declarations: true
|
||||
unnecessary_overrides: true
|
||||
unnecessary_parenthesis: true
|
||||
unnecessary_raw_strings: true
|
||||
unnecessary_string_escapes: true
|
||||
unnecessary_string_interpolations: true
|
||||
unnecessary_this: true
|
||||
use_decorated_box: true
|
||||
use_full_hex_values_for_flutter_colors: true
|
||||
use_function_type_syntax_for_parameters: true
|
||||
use_if_null_to_convert_nulls_to_bools: true
|
||||
use_is_even_rather_than_modulo: true
|
||||
use_late_for_private_fields_and_variables: true
|
||||
use_named_constants: true
|
||||
use_raw_strings: false
|
||||
use_rethrow_when_possible: true
|
||||
use_setters_to_change_properties: true
|
||||
use_string_buffers: true
|
||||
use_test_throws_matchers: true
|
||||
use_to_and_as_if_applicable: true
|
||||
void_checks: true
|
||||
# pub rules
|
||||
depend_on_referenced_packages: true
|
||||
lowercase_with_underscores: true
|
||||
secure_pubspec_urls: false
|
||||
sort_pub_dependencies: false
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
|
@ -1,182 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2022 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:timetable/timetable.dart';
|
||||
|
||||
void main() {
|
||||
runApp(const MaterialApp(home: TimetableDemo()));
|
||||
}
|
||||
|
||||
class TimetableDemo extends StatefulWidget {
|
||||
const TimetableDemo({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<TimetableDemo> createState() => _TimetableDemoState();
|
||||
}
|
||||
|
||||
class _TimetableDemoState extends State<TimetableDemo> {
|
||||
bool _grouped = false;
|
||||
bool _horizontal = true;
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
final List<TimeBlock> blocks = [
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 14, minute: 0),
|
||||
end: const TimeOfDay(hour: 15, minute: 0),
|
||||
id: 0,
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 8, minute: 0),
|
||||
end: const TimeOfDay(hour: 9, minute: 0),
|
||||
id: 1,
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 9, minute: 15),
|
||||
end: const TimeOfDay(hour: 10, minute: 0),
|
||||
id: 1,
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 10, minute: 15),
|
||||
end: const TimeOfDay(hour: 11, minute: 0),
|
||||
child: Container(color: Colors.purple, height: 300, width: 50),
|
||||
childDimension: 300,
|
||||
id: 2,
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 6, minute: 15),
|
||||
end: const TimeOfDay(hour: 7, minute: 0),
|
||||
child: Container(color: Colors.blue, height: 300, width: 300),
|
||||
childDimension: 300,
|
||||
id: 2,
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 18, minute: 0),
|
||||
end: const TimeOfDay(hour: 18, minute: 30),
|
||||
child:
|
||||
const SizedBox(width: 60, height: 60, child: const Text('High Tea')),
|
||||
childDimension: 60,
|
||||
id: 10,
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 18, minute: 0),
|
||||
end: const TimeOfDay(hour: 18, minute: 30),
|
||||
child: const SizedBox(
|
||||
height: 60,
|
||||
width: 60,
|
||||
child: const Text('High Tea'),
|
||||
),
|
||||
childDimension: 60,
|
||||
id: 10,
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 18, minute: 0),
|
||||
end: const TimeOfDay(hour: 18, minute: 30),
|
||||
child: const SizedBox(
|
||||
height: 60,
|
||||
width: 60,
|
||||
child: const Text('High Tea'),
|
||||
),
|
||||
childDimension: 60,
|
||||
id: 10,
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 18, minute: 0),
|
||||
end: const TimeOfDay(hour: 18, minute: 30),
|
||||
child: const SizedBox(
|
||||
height: 50,
|
||||
width: 50,
|
||||
child: const Text('High Tea'),
|
||||
),
|
||||
childDimension: 60,
|
||||
id: 0,
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 14, minute: 0),
|
||||
end: const TimeOfDay(hour: 15, minute: 0),
|
||||
id: 100,
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 14, minute: 0),
|
||||
end: const TimeOfDay(hour: 15, minute: 0),
|
||||
id: 101,
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 14, minute: 0),
|
||||
end: const TimeOfDay(hour: 15, minute: 0),
|
||||
id: 102,
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 14, minute: 0),
|
||||
end: const TimeOfDay(hour: 15, minute: 0),
|
||||
id: 103,
|
||||
),
|
||||
];
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scrollController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var size = MediaQuery.of(context).size;
|
||||
return Scaffold(
|
||||
// backgroundColor: Colors.green,
|
||||
body: Padding(
|
||||
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
|
||||
child: Column(
|
||||
children: [
|
||||
// toggle between horizontal and vertical
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_horizontal = !_horizontal;
|
||||
});
|
||||
},
|
||||
child: Text(_horizontal ? 'Horizontal' : 'Vertical'),
|
||||
),
|
||||
],
|
||||
),
|
||||
// toggle between grouped and ungrouped blocks
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text('Grouped'),
|
||||
Switch(
|
||||
value: _grouped,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_grouped = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(
|
||||
color: Colors.white,
|
||||
child: Timetable(
|
||||
size: Size(size.width, size.height * 0.64),
|
||||
tableDirection: _horizontal ? Axis.horizontal : Axis.vertical,
|
||||
startHour: 3,
|
||||
endHour: 24,
|
||||
timeBlocks: blocks,
|
||||
scrollController: _scrollController,
|
||||
combineBlocks: true,
|
||||
mergeBlocks: _grouped,
|
||||
theme: const TableTheme(
|
||||
tablePaddingStart: 0,
|
||||
blockPaddingBetween: 10,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.9.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.16.0"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cupertino_icons
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
lints:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: lints
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.12"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.5"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.2"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.10.0"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.12"
|
||||
timetable:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.0.2"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
sdks:
|
||||
dart: ">=2.17.6 <3.0.0"
|
||||
flutter: ">=1.17.0"
|
|
@ -1,7 +0,0 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
test('', () {
|
||||
expect(true, isTrue);
|
||||
});
|
||||
}
|
BIN
flutter_timetable.gif
Normal file
BIN
flutter_timetable.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 7 MiB |
38
melos.yaml
Normal file
38
melos.yaml
Normal file
|
@ -0,0 +1,38 @@
|
|||
name: flutter_timetable
|
||||
|
||||
packages:
|
||||
- packages/**
|
||||
|
||||
command:
|
||||
version:
|
||||
branch: master
|
||||
|
||||
scripts:
|
||||
lint:all:
|
||||
run: dart run melos run analyze && dart run melos run format-check
|
||||
description: Run all static analysis checks.
|
||||
|
||||
get:
|
||||
run: |
|
||||
melos exec -c 1 -- "flutter pub get"
|
||||
melos exec --scope="*example*" -c 1 -- "flutter pub get"
|
||||
|
||||
upgrade:
|
||||
run: melos exec -c 1 -- "flutter pub upgrade"
|
||||
|
||||
create:
|
||||
run: melos exec --scope="*example*" -c 1 -- "flutter create ."
|
||||
|
||||
analyze:
|
||||
run: |
|
||||
dart run melos exec -c 1 -- \
|
||||
flutter analyze --fatal-infos
|
||||
description: Run `flutter analyze` for all packages.
|
||||
|
||||
format:
|
||||
run: dart run melos exec dart format .
|
||||
description: Run `dart format` for all packages.
|
||||
|
||||
format-check:
|
||||
run: dart run melos exec dart format . --set-exit-if-changed
|
||||
description: Run `dart format` checks for all packages.
|
1
packages/flutter_timetable_firebase/CHANGELOG.md
Symbolic link
1
packages/flutter_timetable_firebase/CHANGELOG.md
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../CHANGELOG.md
|
1
packages/flutter_timetable_firebase/LICENSE
Symbolic link
1
packages/flutter_timetable_firebase/LICENSE
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../LICENSE
|
1
packages/flutter_timetable_firebase/README.md
Symbolic link
1
packages/flutter_timetable_firebase/README.md
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../README.md
|
43
packages/flutter_timetable_firebase/example/.gitignore
vendored
Normal file
43
packages/flutter_timetable_firebase/example/.gitignore
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
# 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
|
16
packages/flutter_timetable_firebase/example/README.md
Normal file
16
packages/flutter_timetable_firebase/example/README.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
# example
|
||||
|
||||
A new Flutter project.
|
||||
|
||||
## Getting Started
|
||||
|
||||
This project is a starting point for a Flutter application.
|
||||
|
||||
A few resources to get you started if this is your first Flutter project:
|
||||
|
||||
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
||||
|
||||
For help getting started with Flutter development, view the
|
||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||
samples, guidance on mobile development, and a full API reference.
|
|
@ -0,0 +1,28 @@
|
|||
# This file configures the analyzer, which statically analyzes Dart code to
|
||||
# check for errors, warnings, and lints.
|
||||
#
|
||||
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||
# invoked from the command line by running `flutter analyze`.
|
||||
|
||||
# The following line activates a set of recommended lints for Flutter apps,
|
||||
# packages, and plugins designed to encourage good coding practices.
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
linter:
|
||||
# The lint rules applied to this project can be customized in the
|
||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||
# included above or to enable additional rules. A list of all available lints
|
||||
# and their documentation is published at https://dart.dev/lints.
|
||||
#
|
||||
# Instead of disabling a lint rule for the entire project in the
|
||||
# section below, it can also be suppressed for a single line of code
|
||||
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||
# producing the lint.
|
||||
rules:
|
||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
23
packages/flutter_timetable_firebase/example/lib/main.dart
Normal file
23
packages/flutter_timetable_firebase/example/lib/main.dart
Normal file
|
@ -0,0 +1,23 @@
|
|||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:flutter_timetable_firebase/flutter_timetable_firebase.dart';
|
||||
import 'package:flutter_timetable_interface/flutter_timetable_interface.dart';
|
||||
|
||||
class MyRosterModel extends TimetableEvent {
|
||||
const MyRosterModel({
|
||||
required super.end,
|
||||
required super.start,
|
||||
required super.entityId,
|
||||
required super.eventId,
|
||||
this.isSick = false,
|
||||
});
|
||||
|
||||
final bool isSick;
|
||||
}
|
||||
|
||||
final myRosterServiceProvider = Provider(
|
||||
(ref) => FirebaseTimetableService<MyRosterModel>(
|
||||
options: const FirebaseTimetableOptions(timetableCollectionName: 'roster'),
|
||||
),
|
||||
);
|
||||
|
||||
void main() {}
|
31
packages/flutter_timetable_firebase/example/pubspec.yaml
Normal file
31
packages/flutter_timetable_firebase/example/pubspec.yaml
Normal file
|
@ -0,0 +1,31 @@
|
|||
name: flutter_timetable_firebase_example
|
||||
description: Timetable Widget
|
||||
|
||||
publish_to: 'none'
|
||||
|
||||
version: 1.1.0+2
|
||||
|
||||
environment:
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
cupertino_icons: ^1.0.2
|
||||
flutter_timetable_firebase:
|
||||
path: ../
|
||||
flutter_timetable_interface:
|
||||
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub
|
||||
version: ^2.0.0
|
||||
hooks_riverpod: ^2.4.9
|
||||
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
flutter_lints: ^2.0.0
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
|
@ -0,0 +1,30 @@
|
|||
// This is a basic Flutter widget test.
|
||||
//
|
||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||
// utility in the flutter_test package. For example, you can send tap and scroll
|
||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||
// tree, read text, and verify that the values of widget properties are correct.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:example/main.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
// Build our app and trigger a frame.
|
||||
await tester.pumpWidget(const MyApp());
|
||||
|
||||
// Verify that our counter starts at 0.
|
||||
expect(find.text('0'), findsOneWidget);
|
||||
expect(find.text('1'), findsNothing);
|
||||
|
||||
// Tap the '+' icon and trigger a frame.
|
||||
await tester.tap(find.byIcon(Icons.add));
|
||||
await tester.pump();
|
||||
|
||||
// Verify that our counter has incremented.
|
||||
expect(find.text('0'), findsNothing);
|
||||
expect(find.text('1'), findsOneWidget);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
// SPDX-FileCopyrightText: 2023 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
library flutter_timetable_firebase;
|
||||
|
||||
export 'src/config/firebase_timetable_options.dart';
|
||||
export 'src/services/firebase_timetable_service.dart';
|
|
@ -0,0 +1,29 @@
|
|||
// SPDX-FileCopyrightText: 2023 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@immutable
|
||||
class FirebaseTimetableOptions {
|
||||
const FirebaseTimetableOptions({
|
||||
this.timetableCollectionName = 'timetable',
|
||||
this.cachingStrategy = TimetableCachingStrategy.alwaysFetch,
|
||||
});
|
||||
// the collection reference name
|
||||
final String timetableCollectionName;
|
||||
|
||||
/// Changes the Firebase Timetable Service to use different caching approaches
|
||||
final TimetableCachingStrategy cachingStrategy;
|
||||
}
|
||||
|
||||
enum TimetableCachingStrategy {
|
||||
// Everytime the timetable is requested it will be fetched from the database
|
||||
alwaysFetch,
|
||||
// if you use fetchOnce the timetable events will be fetched only once
|
||||
fetchOnce,
|
||||
// will first be fetched and after that updates will be listened to
|
||||
fetchOnceAndListen,
|
||||
// if you use listen the timetable events will be updated in real time
|
||||
listen,
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_timetable_firebase/src/config/firebase_timetable_options.dart';
|
||||
import 'package:flutter_timetable_interface/flutter_timetable_interface.dart';
|
||||
|
||||
class FirebaseTimetableService<Event extends TimetableEvent>
|
||||
with ChangeNotifier
|
||||
implements TimetableService<Event> {
|
||||
FirebaseTimetableService({
|
||||
FirebaseApp? app,
|
||||
options = const FirebaseTimetableOptions(),
|
||||
}) {
|
||||
var appInstance = app ?? Firebase.app();
|
||||
_db = FirebaseFirestore.instanceFor(app: appInstance);
|
||||
_options = options;
|
||||
}
|
||||
|
||||
late FirebaseTimetableOptions _options;
|
||||
late FirebaseFirestore _db;
|
||||
|
||||
@override
|
||||
Future<void> addEvent(Event event) async {
|
||||
event.toJson();
|
||||
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> checkForConflict(Event event, DateTime day) async {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deleteEvent(Event event) async {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Event>> fetchEventsForDay(DateTime day,
|
||||
{String? category}) async {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
List<Event> getEventsForDay(DateTime day, {String? category}) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateEvent(Event event) async {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
27
packages/flutter_timetable_firebase/pubspec.yaml
Normal file
27
packages/flutter_timetable_firebase/pubspec.yaml
Normal file
|
@ -0,0 +1,27 @@
|
|||
# SPDX-FileCopyrightText: 2023 Iconica
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
name: flutter_timetable_firebase
|
||||
description: A new Flutter package project.
|
||||
version: 2.0.0
|
||||
repository: https://github.com/Iconica-Development/flutter_timetable
|
||||
|
||||
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub
|
||||
|
||||
environment:
|
||||
sdk: ">=3.1.0 <4.0.0"
|
||||
flutter: ">=1.17.0"
|
||||
|
||||
dependencies:
|
||||
cloud_firestore: ^4.13.3
|
||||
firebase_core: ^2.24.0
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_timetable_interface:
|
||||
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub
|
||||
version: ^2.0.0
|
||||
|
||||
|
||||
dev_dependencies:
|
||||
flutter_lints: ^2.0.0
|
1
packages/flutter_timetable_interface/CHANGELOG.md
Symbolic link
1
packages/flutter_timetable_interface/CHANGELOG.md
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../CHANGELOG.md
|
1
packages/flutter_timetable_interface/LICENSE
Symbolic link
1
packages/flutter_timetable_interface/LICENSE
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../LICENSE
|
1
packages/flutter_timetable_interface/README.md
Symbolic link
1
packages/flutter_timetable_interface/README.md
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../README.md
|
|
@ -0,0 +1,4 @@
|
|||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
|
@ -0,0 +1,8 @@
|
|||
// SPDX-FileCopyrightText: 2023 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
library flutter_timetable_interface;
|
||||
|
||||
export 'src/models/timetable_event.dart';
|
||||
export 'src/services/timetable_service.dart';
|
|
@ -0,0 +1,45 @@
|
|||
// SPDX-FileCopyrightText: 2023 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@immutable
|
||||
class TimetableEvent {
|
||||
/// The model used for a [Block] in a [TimeTable] which can contain a Widget.
|
||||
const TimetableEvent({
|
||||
required this.start,
|
||||
required this.end,
|
||||
required this.entityId,
|
||||
required this.eventId,
|
||||
this.category,
|
||||
});
|
||||
|
||||
/// The date at which the event starts
|
||||
final DateTime start;
|
||||
|
||||
/// The date at which the event ends
|
||||
final DateTime end;
|
||||
|
||||
/// The unique identifier of the event
|
||||
/// This is used to store the events
|
||||
final String eventId;
|
||||
|
||||
/// The identifier of the entity that the event belongs to
|
||||
/// This is used to check for conflicts between entities
|
||||
final String entityId;
|
||||
|
||||
/// This can be used to filter events
|
||||
final String? category;
|
||||
|
||||
// tojson method and a factory fromJson contructor
|
||||
Map<String, dynamic> toJson() => {};
|
||||
|
||||
factory TimetableEvent.fromJson(String eventId, Map<String, dynamic> json) =>
|
||||
TimetableEvent(
|
||||
start: json['start'],
|
||||
end: json['end'],
|
||||
entityId: json[''],
|
||||
eventId: eventId,
|
||||
);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
abstract class TimetableService<Event> with ChangeNotifier {
|
||||
Future<List<Event>> fetchEventsForDay(DateTime day, {String? category});
|
||||
List<Event> getEventsForDay(DateTime day, {String? category});
|
||||
Future<void> addEvent(Event event);
|
||||
Future<void> updateEvent(Event event);
|
||||
Future<void> deleteEvent(Event event);
|
||||
Future<bool> checkForConflict(Event event, DateTime day);
|
||||
}
|
21
packages/flutter_timetable_interface/pubspec.yaml
Normal file
21
packages/flutter_timetable_interface/pubspec.yaml
Normal file
|
@ -0,0 +1,21 @@
|
|||
# SPDX-FileCopyrightText: 2023 Iconica
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
name: flutter_timetable_interface
|
||||
description: A new Flutter package project.
|
||||
version: 2.0.0
|
||||
repository: https://github.com/Iconica-Development/flutter_timetable
|
||||
|
||||
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub
|
||||
|
||||
environment:
|
||||
sdk: ">=3.1.0 <4.0.0"
|
||||
flutter: ">=1.17.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
dev_dependencies:
|
||||
flutter_lints: ^2.0.0
|
1
packages/flutter_timetable_view/CHANGELOG.md
Symbolic link
1
packages/flutter_timetable_view/CHANGELOG.md
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../CHANGELOG.md
|
1
packages/flutter_timetable_view/LICENSE
Symbolic link
1
packages/flutter_timetable_view/LICENSE
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../LICENSE
|
1
packages/flutter_timetable_view/README.md
Symbolic link
1
packages/flutter_timetable_view/README.md
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../README.md
|
4
packages/flutter_timetable_view/analysis_options.yaml
Normal file
4
packages/flutter_timetable_view/analysis_options.yaml
Normal file
|
@ -0,0 +1,4 @@
|
|||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
|
@ -19,7 +19,7 @@ migrate_working_dir/
|
|||
# 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/
|
||||
.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
|
@ -45,3 +45,6 @@ app.*.map.json
|
|||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
|
||||
pubspec.lock
|
||||
.metadata
|
|
@ -0,0 +1,4 @@
|
|||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
172
packages/flutter_timetable_view/example/lib/main.dart
Normal file
172
packages/flutter_timetable_view/example/lib/main.dart
Normal file
|
@ -0,0 +1,172 @@
|
|||
// SPDX-FileCopyrightText: 2022 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_timetable_view/flutter_timetable_view.dart';
|
||||
|
||||
void main() {
|
||||
runApp(const MaterialApp(home: TimetableDemo()));
|
||||
}
|
||||
|
||||
class TimetableDemo extends StatefulWidget {
|
||||
const TimetableDemo({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<TimetableDemo> createState() => _TimetableDemoState();
|
||||
}
|
||||
|
||||
class _TimetableDemoState extends State<TimetableDemo> {
|
||||
bool _grouped = false;
|
||||
bool _horizontal = true;
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
final List<TimeBlock> blocks = [
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 8, minute: 0),
|
||||
end: const TimeOfDay(hour: 9, minute: 0),
|
||||
child: Container(
|
||||
color: Colors.red,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
'Exercise',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
id: 3,
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 10, minute: 0),
|
||||
end: const TimeOfDay(hour: 12, minute: 0),
|
||||
child: Container(
|
||||
color: Colors.orange,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
'Brunch',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
childDimension: 300,
|
||||
id: 1,
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 14, minute: 0),
|
||||
end: const TimeOfDay(hour: 15, minute: 0),
|
||||
id: 100,
|
||||
child: const SizedBox(
|
||||
height: 300,
|
||||
child: Text(
|
||||
'Clean Living Room',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
)),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 14, minute: 0),
|
||||
end: const TimeOfDay(hour: 15, minute: 0),
|
||||
id: 101,
|
||||
child: const SizedBox(
|
||||
height: 200,
|
||||
child: Text(
|
||||
'Clean Kitchen',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
)),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 14, minute: 0),
|
||||
end: const TimeOfDay(hour: 15, minute: 0),
|
||||
id: 102,
|
||||
child: const SizedBox(
|
||||
height: 100,
|
||||
child: Text(
|
||||
'Clean Bathroom',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 14, minute: 0),
|
||||
end: const TimeOfDay(hour: 15, minute: 0),
|
||||
id: 103,
|
||||
child: const SizedBox(
|
||||
height: 50,
|
||||
child: Text(
|
||||
'Clean Toilet',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scrollController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var size = MediaQuery.of(context).size;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Timetable Demo'),
|
||||
),
|
||||
// backgroundColor: Colors.green,
|
||||
body: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
// toggle between horizontal and vertical
|
||||
const Text('Axis horizontal'),
|
||||
Switch(
|
||||
value: _horizontal,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_horizontal = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
// toggle between grouped and ungrouped blocks
|
||||
const Text('Grouped'),
|
||||
Switch(
|
||||
value: _grouped,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_grouped = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
color: Colors.white,
|
||||
child: Timetable(
|
||||
onOverScroll: () {},
|
||||
onUnderScroll: () {},
|
||||
hoursOffset: 6,
|
||||
sortByIdAscending: true,
|
||||
size: Size(size.width, size.height * 0.64),
|
||||
tableDirection: _horizontal ? Axis.horizontal : Axis.vertical,
|
||||
startHour: 0,
|
||||
endHour: 24,
|
||||
timeBlocks: blocks,
|
||||
scrollController: _scrollController,
|
||||
combineBlocks: true,
|
||||
mergeBlocks: _grouped,
|
||||
theme: const TableTheme(
|
||||
tablePaddingStart: 0,
|
||||
blockPaddingBetween: 10,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,20 +1,22 @@
|
|||
name: timetable_example
|
||||
name: flutter_timetable_view_example
|
||||
description: Timetable Widget
|
||||
|
||||
publish_to: 'none'
|
||||
|
||||
version: 1.0.0+1
|
||||
version: 1.1.0+2
|
||||
|
||||
environment:
|
||||
sdk: ">=2.17.6 <3.0.0"
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
cupertino_icons: ^1.0.2
|
||||
timetable:
|
||||
flutter_timetable_view:
|
||||
path: ../
|
||||
flutter_timetable_interface:
|
||||
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
|
@ -0,0 +1,7 @@
|
|||
// import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
// void main() {
|
||||
// test('', () {
|
||||
// expect(true, isTrue);
|
||||
// });
|
||||
// }
|
|
@ -2,10 +2,10 @@
|
|||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
library timetable;
|
||||
library flutter_timetable;
|
||||
|
||||
export 'src/models/table_theme.dart';
|
||||
export 'src/models/time_block.dart';
|
||||
export 'src/timetable.dart';
|
||||
export 'src/widgets/block.dart';
|
||||
export 'src/widgets/table.dart';
|
||||
export 'src/models/time_block.dart';
|
|
@ -3,7 +3,7 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:timetable/src/models/time_block.dart';
|
||||
import 'package:flutter_timetable_view/src/models/time_block.dart';
|
||||
|
||||
/// Combine blocks that have the same id and the same time.
|
||||
List<TimeBlock> combineBlocksWithId(List<TimeBlock> blocks) {
|
||||
|
@ -39,6 +39,7 @@ List<TimeBlock> combineBlocksWithId(List<TimeBlock> blocks) {
|
|||
return newBlocks;
|
||||
}
|
||||
|
||||
/// Combines grouped blocks into one block.
|
||||
void _combineGroupedBlocks(
|
||||
List<List<TimeBlock>> groupedBlocks,
|
||||
List<TimeBlock> newBlocks,
|
||||
|
@ -74,6 +75,10 @@ void _combineGroupedBlocks(
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks if a block with a certain id exists in the grouped blocks.
|
||||
///
|
||||
/// Returns true if a block with the same id, start time, and end time exists in the grouped blocks list.
|
||||
/// Otherwise, returns false.
|
||||
bool _checkIfBlockWithIdExists(
|
||||
List<List<TimeBlock>> groupedBlocks,
|
||||
TimeBlock block,
|
|
@ -6,11 +6,12 @@ import 'dart:math';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:timetable/src/block_service.dart';
|
||||
import 'package:timetable/src/models/table_theme.dart';
|
||||
import 'package:timetable/src/models/time_block.dart';
|
||||
import 'package:timetable/src/widgets/block.dart';
|
||||
import 'package:timetable/src/widgets/table.dart' as table;
|
||||
import 'package:flutter_timetable_view/src/block_service.dart';
|
||||
import 'package:flutter_timetable_view/src/models/table_theme.dart';
|
||||
import 'package:flutter_timetable_view/src/models/time_block.dart';
|
||||
import 'package:flutter_timetable_view/src/widgets/block.dart';
|
||||
|
||||
import 'package:flutter_timetable_view/src/widgets/table.dart' as table;
|
||||
|
||||
class Timetable extends StatefulWidget {
|
||||
/// [Timetable] widget that displays a timetable with [TimeBlock]s.
|
||||
|
@ -22,18 +23,34 @@ class Timetable extends StatefulWidget {
|
|||
this.tableDirection = Axis.vertical,
|
||||
this.timeBlocks = const [],
|
||||
this.size,
|
||||
this.initialScrollTime,
|
||||
this.scrollController,
|
||||
this.scrollPhysics,
|
||||
this.hoursOffset = 0,
|
||||
this.startHour = 0,
|
||||
this.endHour = 24,
|
||||
this.blockDimension = 50,
|
||||
this.blockColor = const Color(0x80FF0000),
|
||||
this.blockColor = Colors.blue,
|
||||
this.hourDimension = 80,
|
||||
this.theme = const TableTheme(),
|
||||
this.mergeBlocks = false,
|
||||
this.combineBlocks = true,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
this.sortByIdAscending = false,
|
||||
this.sortByStartTime = false,
|
||||
this.onOverScroll,
|
||||
this.onUnderScroll,
|
||||
this.scrollTriggerOffset = 120,
|
||||
this.scrollJumpToOffset = 115,
|
||||
super.key,
|
||||
}) : assert(
|
||||
scrollTriggerOffset > scrollJumpToOffset,
|
||||
'ScrollTriggerOffset cannot be smaller'
|
||||
' then the scrollJumpToOffset.',
|
||||
),
|
||||
assert(
|
||||
!(mergeBlocks && sortByIdAscending),
|
||||
'mergeBlocks and sortByIdAscending'
|
||||
' cannot be enabled at the same time.');
|
||||
|
||||
/// The Axis in which the table is layed out.
|
||||
final Axis tableDirection;
|
||||
|
@ -47,6 +64,10 @@ class Timetable extends StatefulWidget {
|
|||
/// Hour at which the timetable ends.
|
||||
final int endHour;
|
||||
|
||||
/// The time offset to increase all hour labels with
|
||||
/// this is used to make the timetable start at a different time and go past midnight.
|
||||
final int hoursOffset;
|
||||
|
||||
/// The time blocks that will be displayed in the timetable.
|
||||
final List<TimeBlock> timeBlocks;
|
||||
|
||||
|
@ -63,6 +84,9 @@ class Timetable extends StatefulWidget {
|
|||
/// The theme of the timetable.
|
||||
final TableTheme theme;
|
||||
|
||||
/// The initial time to scroll to if there are no timeblocks. If nothing is provided it will scroll to the current time or to the first block if there is one.
|
||||
final TimeOfDay? initialScrollTime;
|
||||
|
||||
/// The scroll controller to control the scrolling of the timetable.
|
||||
final ScrollController? scrollController;
|
||||
|
||||
|
@ -76,6 +100,21 @@ class Timetable extends StatefulWidget {
|
|||
/// If blocks have the same id and time they will be combined into one block.
|
||||
final bool combineBlocks;
|
||||
|
||||
/// Whether or not to sort blocks by their ID in ascending order.
|
||||
final bool sortByIdAscending;
|
||||
|
||||
/// Whether or not to sort blocks by their StartTime.
|
||||
final bool sortByStartTime;
|
||||
|
||||
/// The offset which trigger the jump to either the previous or next page. Can't be lower then [scrollJumpToOffset].
|
||||
final double scrollTriggerOffset;
|
||||
|
||||
/// When the jump is triggered this offset will be jumped outside of the min or max offset. Can't be higher then [scrollTriggerOffset].
|
||||
final double scrollJumpToOffset;
|
||||
|
||||
final void Function()? onUnderScroll;
|
||||
final void Function()? onOverScroll;
|
||||
|
||||
@override
|
||||
State<Timetable> createState() => _TimetableState();
|
||||
}
|
||||
|
@ -86,11 +125,46 @@ class _TimetableState extends State<Timetable> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_scrollController =
|
||||
widget.scrollController ?? ScrollController(initialScrollOffset: 0);
|
||||
if (widget.timeBlocks.isNotEmpty) {
|
||||
_scrollToFirstBlock();
|
||||
} else {
|
||||
_scrollToInitialTime();
|
||||
}
|
||||
|
||||
if (widget.onUnderScroll != null && widget.onOverScroll != null) {
|
||||
_scrollController.addListener(() {
|
||||
if (_scrollController.offset -
|
||||
_scrollController.position.maxScrollExtent >
|
||||
widget.scrollTriggerOffset) {
|
||||
if (widget.onOverScroll != null) {
|
||||
_scrollController.jumpTo(
|
||||
_scrollController.position.minScrollExtent -
|
||||
widget.scrollJumpToOffset);
|
||||
|
||||
widget.onOverScroll?.call();
|
||||
}
|
||||
} else if (_scrollController.position.minScrollExtent -
|
||||
_scrollController.offset >
|
||||
widget.scrollTriggerOffset) {
|
||||
if (widget.onUnderScroll != null) {
|
||||
_scrollController.jumpTo(
|
||||
_scrollController.position.maxScrollExtent +
|
||||
widget.scrollJumpToOffset);
|
||||
|
||||
widget.onUnderScroll?.call();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
int compareTimeOfDay(TimeOfDay time1, TimeOfDay time2) {
|
||||
var totalMinutes1 = time1.hour * 60 + time1.minute;
|
||||
var totalMinutes2 = time2.hour * 60 + time2.minute;
|
||||
return totalMinutes1.compareTo(totalMinutes2);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -109,6 +183,18 @@ class _TimetableState extends State<Timetable> {
|
|||
} else {
|
||||
blocks = widget.timeBlocks;
|
||||
}
|
||||
|
||||
if (widget.sortByIdAscending) {
|
||||
// if the id is zero then put it at the end
|
||||
blocks.sort((a, b) => (a.id != 0 ? a.id : double.infinity).compareTo(
|
||||
(b.id != 0 ? b.id : double.infinity),
|
||||
));
|
||||
}
|
||||
|
||||
if (widget.sortByStartTime) {
|
||||
blocks.sort((a, b) => compareTimeOfDay(a.start, b.start));
|
||||
}
|
||||
|
||||
var linePadding = _calculateTableTextSize().width;
|
||||
return SizedBox(
|
||||
width: widget.size?.width,
|
||||
|
@ -121,6 +207,7 @@ class _TimetableState extends State<Timetable> {
|
|||
alignment: Alignment.topLeft,
|
||||
children: [
|
||||
table.Table(
|
||||
hoursOffset: widget.hoursOffset,
|
||||
tableDirection: widget.tableDirection,
|
||||
startHour: widget.startHour,
|
||||
endHour: widget.endHour,
|
||||
|
@ -224,32 +311,28 @@ class _TimetableState extends State<Timetable> {
|
|||
);
|
||||
}
|
||||
|
||||
Size _calculateTableStart(Axis axis) {
|
||||
return Size(
|
||||
(axis == Axis.horizontal)
|
||||
? _calculateTableTextSize().width / 2
|
||||
: _calculateTableTextSize().width +
|
||||
widget.theme.tablePaddingStart +
|
||||
widget.theme.tableTextOffset,
|
||||
(axis == Axis.vertical)
|
||||
? _calculateTableTextSize().height / 2
|
||||
: _calculateTableTextSize().height,
|
||||
);
|
||||
}
|
||||
Size _calculateTableStart(Axis axis) => Size(
|
||||
(axis == Axis.horizontal)
|
||||
? _calculateTableTextSize().width / 2
|
||||
: _calculateTableTextSize().width +
|
||||
widget.theme.tablePaddingStart +
|
||||
widget.theme.tableTextOffset,
|
||||
(axis == Axis.vertical)
|
||||
? _calculateTableTextSize().height / 2
|
||||
: _calculateTableTextSize().height,
|
||||
);
|
||||
|
||||
Widget _showBlock(TimeBlock block, {double linePadding = 0}) {
|
||||
return Block(
|
||||
blockDirection: widget.tableDirection,
|
||||
linePadding: linePadding,
|
||||
start: block.start,
|
||||
end: block.end,
|
||||
startHour: widget.startHour,
|
||||
hourDimension: widget.hourDimension,
|
||||
blockDimension: widget.blockDimension,
|
||||
blockColor: widget.blockColor,
|
||||
child: block.child,
|
||||
);
|
||||
}
|
||||
Widget _showBlock(TimeBlock block, {double linePadding = 0}) => Block(
|
||||
blockDirection: widget.tableDirection,
|
||||
linePadding: linePadding,
|
||||
start: block.start,
|
||||
end: block.end,
|
||||
startHour: widget.startHour,
|
||||
hourDimension: widget.hourDimension,
|
||||
blockDimension: widget.blockDimension,
|
||||
blockColor: widget.blockColor,
|
||||
child: block.child,
|
||||
);
|
||||
|
||||
void _scrollToFirstBlock() {
|
||||
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||
|
@ -271,19 +354,32 @@ class _TimetableState extends State<Timetable> {
|
|||
});
|
||||
}
|
||||
|
||||
Size _calculateTableTextSize() {
|
||||
return (TextPainter(
|
||||
text: TextSpan(
|
||||
text: '22:22',
|
||||
style: widget.theme.timeStyle ?? Theme.of(context).textTheme.bodyText1,
|
||||
),
|
||||
maxLines: 1,
|
||||
textScaleFactor: MediaQuery.of(context).textScaleFactor,
|
||||
textDirection: TextDirection.ltr,
|
||||
)..layout())
|
||||
.size;
|
||||
void _scrollToInitialTime() {
|
||||
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||
var startingTime = widget.initialScrollTime ?? TimeOfDay.now();
|
||||
var initialOffset =
|
||||
(widget.hourDimension * (widget.endHour - widget.startHour)) *
|
||||
((startingTime.hour - widget.startHour) /
|
||||
(widget.endHour - widget.startHour)) +
|
||||
_calculateTableTextSize().width / 2;
|
||||
_scrollController.jumpTo(
|
||||
initialOffset,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Size _calculateTableTextSize() => (TextPainter(
|
||||
text: TextSpan(
|
||||
text: '22:22',
|
||||
style:
|
||||
widget.theme.timeStyle ?? Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
maxLines: 1,
|
||||
textScaler: MediaQuery.of(context).textScaler,
|
||||
textDirection: TextDirection.ltr,
|
||||
)..layout())
|
||||
.size;
|
||||
|
||||
double calculateTableHeight() {
|
||||
var sum = 0.0;
|
||||
if (widget.mergeBlocks || widget.combineBlocks) {
|
|
@ -13,7 +13,7 @@ class Block extends StatelessWidget {
|
|||
required this.blockDimension,
|
||||
required this.hourDimension,
|
||||
required this.blockDirection,
|
||||
this.blockColor = const Color(0x80FF0000),
|
||||
this.blockColor = Colors.blue,
|
||||
this.linePadding = 8,
|
||||
this.child,
|
||||
Key? key,
|
||||
|
@ -49,6 +49,7 @@ class Block extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: blockColor,
|
||||
margin: EdgeInsets.only(
|
||||
top: (blockDirection == Axis.vertical)
|
||||
? (((start.hour - startHour) * Duration.minutesPerHour) +
|
||||
|
@ -76,10 +77,9 @@ class Block extends StatelessWidget {
|
|||
_sizePerMinute()
|
||||
: null,
|
||||
child: child ??
|
||||
Container(
|
||||
SizedBox(
|
||||
height: (blockDirection == Axis.horizontal) ? blockDimension : 0,
|
||||
width: (blockDirection == Axis.vertical) ? blockDimension : 0,
|
||||
color: blockColor,
|
||||
),
|
||||
);
|
||||
}
|
|
@ -3,20 +3,21 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:timetable/src/models/table_theme.dart';
|
||||
import 'package:flutter_timetable_view/src/models/table_theme.dart';
|
||||
|
||||
class Table extends StatelessWidget {
|
||||
/// The [Table] to draw an overview of timerange with corresponding hour lines
|
||||
const Table({
|
||||
required this.startHour,
|
||||
required this.endHour,
|
||||
this.hoursOffset = 0,
|
||||
this.size,
|
||||
this.tableDirection = Axis.vertical,
|
||||
this.hourDimension = 80,
|
||||
this.tableOffset = 20,
|
||||
this.theme = const TableTheme(),
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
super.key,
|
||||
});
|
||||
|
||||
/// The [Axis] in which the table is layed out.
|
||||
final Axis tableDirection;
|
||||
|
@ -30,6 +31,9 @@ class Table extends StatelessWidget {
|
|||
/// The hour the table ends at.
|
||||
final int endHour;
|
||||
|
||||
/// The time offset to increase all hour labels with
|
||||
final int hoursOffset;
|
||||
|
||||
/// The length in pixel of a single hour in the table.
|
||||
final double hourDimension;
|
||||
|
||||
|
@ -55,10 +59,10 @@ class Table extends StatelessWidget {
|
|||
Column(
|
||||
children: [
|
||||
Text(
|
||||
'${((i == 24) ? '00' : i.toString()).padLeft(2, '0')}'
|
||||
'${(((i + hoursOffset) == 24) ? '00' : ((i + hoursOffset) % 24).toString()).padLeft(2, '0')}'
|
||||
':00',
|
||||
style: theme.timeStyle ??
|
||||
Theme.of(context).textTheme.bodyText1,
|
||||
Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
SizedBox(height: theme.tableTextOffset),
|
||||
Container(
|
||||
|
@ -124,9 +128,9 @@ class Table extends StatelessWidget {
|
|||
Row(
|
||||
children: [
|
||||
Text(
|
||||
'${i.toString().padLeft(2, '0')}:00',
|
||||
'${((i + hoursOffset) % 24).toString().padLeft(2, '0')}:00',
|
||||
style: theme.timeStyle ??
|
||||
Theme.of(context).textTheme.bodyText1,
|
||||
Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
SizedBox(
|
||||
width: theme.tableTextOffset,
|
||||
|
@ -183,7 +187,7 @@ class Table extends StatelessWidget {
|
|||
var textPainter = TextPainter(
|
||||
text: TextSpan(
|
||||
text: text,
|
||||
style: theme.timeStyle ?? Theme.of(context).textTheme.bodyText1,
|
||||
style: theme.timeStyle ?? Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
textDirection: TextDirection.ltr,
|
||||
)..layout();
|
22
packages/flutter_timetable_view/pubspec.yaml
Normal file
22
packages/flutter_timetable_view/pubspec.yaml
Normal file
|
@ -0,0 +1,22 @@
|
|||
name: flutter_timetable_view
|
||||
description: Flutter package to create a Timetable Widget that display blocks of widgets inside a timetable.
|
||||
version: 2.0.0
|
||||
repository: https://github.com/Iconica-Development/flutter_timetable
|
||||
|
||||
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub
|
||||
|
||||
environment:
|
||||
sdk: ">=3.2.0 <4.0.0"
|
||||
flutter: ">=1.17.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_timetable_interface:
|
||||
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub
|
||||
version: ^2.0.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^2.0.0
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:timetable/src/block_service.dart';
|
||||
import 'package:timetable/timetable.dart';
|
||||
import 'package:flutter_timetable_view/src/block_service.dart';
|
||||
import 'package:flutter_timetable_view/src/models/time_block.dart';
|
||||
|
||||
void main() {
|
||||
group('test combineBlocksWithId', () {
|
19
pubspec.yaml
19
pubspec.yaml
|
@ -1,19 +1,6 @@
|
|||
name: timetable
|
||||
description: Flutter package to create a Timetable Widget that display blocks of widgets inside a timetable.
|
||||
version: 0.0.2
|
||||
repository: https://github.com/Iconica-Development/timetable
|
||||
name: flutter_timetable_workspace
|
||||
|
||||
environment:
|
||||
sdk: ">=2.17.6 <3.0.0"
|
||||
flutter: ">=1.17.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
sdk: '>=3.1.0 <4.0.0'
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^2.0.0
|
||||
|
||||
flutter:
|
||||
melos: ^3.0.1
|
||||
|
|
Loading…
Reference in a new issue