mirror of
https://github.com/Iconica-Development/flutter_timetable.git
synced 2025-05-18 19:43:43 +02:00
Compare commits
9 commits
Author | SHA1 | Date | |
---|---|---|---|
|
79f31f2552 | ||
|
0136f84a10 | ||
|
333c189428 | ||
|
9bac97f831 | ||
|
8b333e7bb7 | ||
|
32b9f9f2c5 | ||
|
f031828067 | ||
|
651ed33cfc | ||
|
93b25c7db6 |
51 changed files with 792 additions and 53 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
|
12
.github/workflows/flutter.yml
vendored
12
.github/workflows/flutter.yml
vendored
|
@ -1,12 +0,0 @@
|
|||
name: Iconica Standard Component CI Workflow
|
||||
# Workflow Caller version: 1.0.0
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
call-global-iconica-workflow:
|
||||
uses: Iconica-Development/.github/.github/workflows/component-ci.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
|
19
.gitignore
vendored
19
.gitignore
vendored
|
@ -23,16 +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
|
||||
|
|
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -26,3 +26,17 @@
|
|||
## [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:
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ Please file any issues, bugs or feature request as an issue on our [GitHub](http
|
|||
|
||||
## Want to contribute
|
||||
|
||||
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).
|
||||
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
|
||||
|
||||
|
|
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
|
|
@ -3,7 +3,7 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_timetable/timetable.dart';
|
||||
import 'package:flutter_timetable_view/flutter_timetable_view.dart';
|
||||
|
||||
void main() {
|
||||
runApp(const MaterialApp(home: TimetableDemo()));
|
||||
|
@ -34,7 +34,7 @@ class _TimetableDemoState extends State<TimetableDemo> {
|
|||
),
|
||||
),
|
||||
),
|
||||
id: 1,
|
||||
id: 3,
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 10, minute: 0),
|
||||
|
@ -50,7 +50,7 @@ class _TimetableDemoState extends State<TimetableDemo> {
|
|||
),
|
||||
),
|
||||
childDimension: 300,
|
||||
id: 3,
|
||||
id: 1,
|
||||
),
|
||||
TimeBlock(
|
||||
start: const TimeOfDay(hour: 14, minute: 0),
|
||||
|
@ -150,6 +150,7 @@ class _TimetableDemoState extends State<TimetableDemo> {
|
|||
onOverScroll: () {},
|
||||
onUnderScroll: () {},
|
||||
hoursOffset: 6,
|
||||
sortByIdAscending: true,
|
||||
size: Size(size.width, size.height * 0.64),
|
||||
tableDirection: _horizontal ? Axis.horizontal : Axis.vertical,
|
||||
startHour: 0,
|
|
@ -1,4 +1,4 @@
|
|||
name: timetable_example
|
||||
name: flutter_timetable_view_example
|
||||
description: Timetable Widget
|
||||
|
||||
publish_to: 'none'
|
||||
|
@ -13,8 +13,10 @@ dependencies:
|
|||
sdk: flutter
|
||||
|
||||
cupertino_icons: ^1.0.2
|
||||
flutter_timetable:
|
||||
flutter_timetable_view:
|
||||
path: ../
|
||||
flutter_timetable_interface:
|
||||
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
|
@ -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:flutter_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:flutter_timetable/src/block_service.dart';
|
||||
import 'package:flutter_timetable/src/models/table_theme.dart';
|
||||
import 'package:flutter_timetable/src/models/time_block.dart';
|
||||
import 'package:flutter_timetable/src/widgets/block.dart';
|
||||
import 'package:flutter_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.
|
||||
|
@ -34,15 +35,22 @@ class Timetable extends StatefulWidget {
|
|||
this.theme = const TableTheme(),
|
||||
this.mergeBlocks = false,
|
||||
this.combineBlocks = true,
|
||||
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(
|
||||
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;
|
||||
|
@ -92,6 +100,12 @@ 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;
|
||||
|
||||
|
@ -147,6 +161,12 @@ class _TimetableState extends State<Timetable> {
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
void dispose() {
|
||||
if (widget.scrollController == null) {
|
||||
|
@ -163,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,
|
||||
|
@ -343,7 +375,7 @@ class _TimetableState extends State<Timetable> {
|
|||
widget.theme.timeStyle ?? Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
maxLines: 1,
|
||||
textScaleFactor: MediaQuery.of(context).textScaleFactor,
|
||||
textScaler: MediaQuery.of(context).textScaler,
|
||||
textDirection: TextDirection.ltr,
|
||||
)..layout())
|
||||
.size;
|
|
@ -3,7 +3,7 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_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
|
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:flutter_timetable/src/block_service.dart';
|
||||
import 'package:flutter_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: flutter_timetable
|
||||
description: Flutter package to create a Timetable Widget that display blocks of widgets inside a timetable.
|
||||
version: 1.3.0
|
||||
repository: https://github.com/Iconica-Development/timetable
|
||||
name: flutter_timetable_workspace
|
||||
|
||||
environment:
|
||||
sdk: ">=3.0.0 <4.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