mirror of
https://github.com/hanskokx/arcane_helper_utils.git
synced 2026-05-14 02:19:09 +02:00
+29
@@ -0,0 +1,29 @@
|
|||||||
|
# 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
|
||||||
|
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||||
|
/pubspec.lock
|
||||||
|
**/doc/api/
|
||||||
|
.dart_tool/
|
||||||
|
build/
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# 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: "4cf269e36de2573851eaef3c763994f8f9be494d"
|
||||||
|
channel: "stable"
|
||||||
|
|
||||||
|
project_type: package
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
## 1.0.0
|
||||||
|
|
||||||
|
* Initial release
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
Contributing
|
||||||
|
============
|
||||||
|
|
||||||
|
[Improvements, bug reports, feature requests welcome][gh-issues].
|
||||||
|
|
||||||
|
- Please include `dart --version` and the package version when reporting bugs.
|
||||||
|
- Code should be formatted with `dartfmt`.
|
||||||
|
- Public methods should have doc comments and test coverage.
|
||||||
|
- Itemize user-facing changes in the `HEAD` section of the `CHANGELOG` file.
|
||||||
|
- Use [well-formatted commit messages][git-log-fmt].
|
||||||
|
|
||||||
|
[gh-issues]: https://github.com/hanskokx/arcane_helper_utils/issues
|
||||||
|
[git-log-fmt]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2024, Hans Kokx
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
@@ -0,0 +1,317 @@
|
|||||||
|
# Overview
|
||||||
|
|
||||||
|
Arcane Helper Utils is a Dart package designed to enhance Dart development by
|
||||||
|
providing utility functions and extensions that simplify common tasks.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Ticker Utility**: A utility class that facilitates time-based actions,
|
||||||
|
perfect for animations or any timing-related operations.
|
||||||
|
- **JSON Converter**: Simplifies the process of converting JSON data into
|
||||||
|
Dart objects.
|
||||||
|
- **DateTime Extensions**: Adds additional functionality to the `DateTime`
|
||||||
|
class, making it easier to format dates and calculate differences.
|
||||||
|
- **String Extensions**: Enhances the `String` class by adding new methods for
|
||||||
|
common transformations and checks, including JWT parsing.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
To use this package in your Dart project, add it to your project's
|
||||||
|
`pubspec.yaml` file:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
dependencies:
|
||||||
|
arcane_helper_utils: any
|
||||||
|
```
|
||||||
|
|
||||||
|
Then import it in your Dart files where needed:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
import 'package:arcane_helper_utils/arcane_helper_utils.dart';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
Here are some examples of how to use the utilities and extensions provided by
|
||||||
|
this package:
|
||||||
|
|
||||||
|
### Ticker
|
||||||
|
|
||||||
|
The `Ticker` can be used as a countdown or interval timer.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final Stream<int> ticker = const Ticker().tick(
|
||||||
|
timeout: Duration(seconds: 30),
|
||||||
|
interval: Duration(seconds: 5)
|
||||||
|
);
|
||||||
|
|
||||||
|
await for (final int ticksRemaining in ticker) {
|
||||||
|
if (ticksRemaining == 0) print("Time's up!");
|
||||||
|
print('Tick! $ticksRemaining');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### JSON Conversion
|
||||||
|
|
||||||
|
These helper methods are used in conjunction with the Freezed package to
|
||||||
|
annotate fields that need to be converted from one data type to another.
|
||||||
|
The available conversions are:
|
||||||
|
|
||||||
|
- `String?` to `int?`
|
||||||
|
- `String?` to `double?`
|
||||||
|
|
||||||
|
Provided the following JSON output, the `valueIsMaybeNull` field will be
|
||||||
|
converted from an empty `String` to `null`, the `valueIsDouble` field will
|
||||||
|
be converted from a `String?` to a `double?`, and the `valueIsInt` field will be
|
||||||
|
converted from a `String?` to an `int?`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"valueIsMaybeNull": "",
|
||||||
|
"valueIsDouble": "123.456",
|
||||||
|
"valueIsInt": "123"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```dart
|
||||||
|
@freezed
|
||||||
|
class MyFreezedClass with _$MyFreezedClass {
|
||||||
|
const factory MyFreezedClass({
|
||||||
|
@DecimalConverter() double? valueIsMaybeNull,
|
||||||
|
@DecimalConverter() double? valueIsDouble,
|
||||||
|
@IntegerConverter() int? valueIsInt,
|
||||||
|
}) = _MyFreezedClass;
|
||||||
|
|
||||||
|
factory MyFreezedClass.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$MyFreezedClassFromJson(json);
|
||||||
|
|
||||||
|
const MyFreezedClass._();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### DateTime Extensions
|
||||||
|
|
||||||
|
These extensions add helpful methods to the `DateTime` class, making it easier
|
||||||
|
to handle common date and time operations such as formatting, comparisons, and
|
||||||
|
calculations.
|
||||||
|
|
||||||
|
These are broken down into the following categories:
|
||||||
|
|
||||||
|
- Start and end of period calculations
|
||||||
|
- Comparison operations
|
||||||
|
- Period information operations
|
||||||
|
|
||||||
|
#### Start and End of Period Calculations
|
||||||
|
|
||||||
|
The following operations are now available on a `DateTime` object:
|
||||||
|
|
||||||
|
- `startOfHour`: Returns a new `DateTime` object where the time stamp is set to
|
||||||
|
the beginning of the given hour.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final DateTime dateTime = DateTime(2019, 1, 1, 13, 45);
|
||||||
|
print(dateTime); // 2019-01-01T13:45:00.0
|
||||||
|
print(dateTime.startOfHour); // 2019-01-01T13:00:00.0
|
||||||
|
```
|
||||||
|
|
||||||
|
- `endOfHour`: Returns a new `DateTime` object where the time stamp is set to
|
||||||
|
the end of the given hour.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final DateTime dateTime = DateTime(2019, 1, 1, 13, 45);
|
||||||
|
print(dateTime); // 2019-01-01T13:45:00.0
|
||||||
|
print(dateTime.endOfHour); // 2019-01-01T13:59:59.999
|
||||||
|
```
|
||||||
|
|
||||||
|
- `startOfDay`: Returns a new `DateTime` object where the time stamp is set to
|
||||||
|
the beginning of the day.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final DateTime dateTime = DateTime(2019, 1, 1, 13, 45);
|
||||||
|
print(dateTime); // 2019-01-01T13:45:00.0
|
||||||
|
print(dateTime.startOfDay); // 2019-01-01T00:00:00.0
|
||||||
|
```
|
||||||
|
|
||||||
|
- `endOfDay`: Returns a new `DateTime` object where the time stamp is set to the
|
||||||
|
end of the day.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final DateTime dateTime = DateTime(2019, 1, 1, 13, 45);
|
||||||
|
print(dateTime); // 2019-01-01T13:45:00.0
|
||||||
|
print(dateTime.endOfDay); // 2019-01-01T23:59:59.9
|
||||||
|
```
|
||||||
|
|
||||||
|
- `startOfWeek`: Returns a new `DateTime` object where the time stamp is set to
|
||||||
|
the beginning of the week (Monday).
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final DateTime dateTime = DateTime(2023, 9, 10);
|
||||||
|
print(dateTime); // 2023-09-10
|
||||||
|
print(dateTime.startOfWeek); // 2023-09-04
|
||||||
|
```
|
||||||
|
|
||||||
|
- `endOfWeek`: Returns a new `DateTime` object where the time stamp is set to
|
||||||
|
the end of the week (Sunday).
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final DateTime dateTime = DateTime(2023, 9, 10);
|
||||||
|
print(dateTime); // 2023-09-10
|
||||||
|
print(dateTime.endOfWeek); // 2023-09-17T23:59:59.999999
|
||||||
|
```
|
||||||
|
|
||||||
|
- `startOfMonth`: Returns a new `DateTime` object where the time stamp is set to
|
||||||
|
the beginning of the month.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final DateTime dateTime = DateTime(2023, 9, 10);
|
||||||
|
print(dateTime); // 2023-09-10
|
||||||
|
print(dateTime.startOfMonth); // 2023-09-01T00:00:00.0
|
||||||
|
```
|
||||||
|
|
||||||
|
- `endOfMonth`: Returns a new `DateTime` object where the time stamp is set to
|
||||||
|
the end of the month.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final DateTime dateTime = DateTime(2023, 9, 10);
|
||||||
|
print(dateTime); // 2023-09-10
|
||||||
|
print(dateTime.endOfMonth); // 2023-09-30T23:59:59.999999
|
||||||
|
```
|
||||||
|
|
||||||
|
- `startOfYear`: Returns a new `DateTime` object where the time stamp is set to
|
||||||
|
the beginning of the year.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final DateTime dateTime = DateTime(2023, 9, 10);
|
||||||
|
print(dateTime); // 2023-09-10
|
||||||
|
print(dateTime.startOfYear); // 2023-01-01T00:00:00.0
|
||||||
|
```
|
||||||
|
|
||||||
|
- `endOfYear`: Returns a new `DateTime` object where the time stamp is set to
|
||||||
|
the end of the year.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final DateTime dateTime = DateTime(2023, 9, 10);
|
||||||
|
print(dateTime); // 2023-09-10
|
||||||
|
print(dateTime.endOfYear); // 2023-12-31T23:59:59.999999
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Comparison Operations
|
||||||
|
|
||||||
|
- `isToday`: Returns `true` if the provided `DateTime` is today, otherwise
|
||||||
|
returns `false`.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final DateTime today = DateTime(2024, 9, 10);
|
||||||
|
final bool notToday = DateTime(2001, 12, 31).isToday; // false
|
||||||
|
```
|
||||||
|
|
||||||
|
- `isSameDayAs`: Compares two `DateTime` objects and returns `true` if they
|
||||||
|
represent the same day.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final DateTime first = DateTime(2001, 1, 1);
|
||||||
|
final DateTime second = DateTime(2001, 1, 2);
|
||||||
|
final DateTime third = DateTime(2001, 1, 1);
|
||||||
|
|
||||||
|
final bool firstAndSecond = first.isSameDayAs(second); // false
|
||||||
|
final bool firstAndThird = first.isSameDayAs(third); // true
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Period Information Operations
|
||||||
|
|
||||||
|
- `daysInMonth`: Returns an `int` with the number of days in a provided month.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final int daysInMonth = DateTime(2024, 9).daysInMonth; // 30
|
||||||
|
```
|
||||||
|
|
||||||
|
- `firstDayOfWeek`: Returns a new `DateTime` object where the time stamp is set
|
||||||
|
to the beginning of the first day (Sunday) of the original `DateTime`'s week.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final DateTime today = DateTime(2024, 9, 10); // Tuesday
|
||||||
|
final DateTime sunday = today.firstDayOfWeek; // Sunday
|
||||||
|
```
|
||||||
|
|
||||||
|
### JWT Parsing
|
||||||
|
|
||||||
|
These extensions enhance the `String` class with JWT-specific functionalities,
|
||||||
|
making it easier to handle JSON Web Tokens directly as `String` objects.
|
||||||
|
|
||||||
|
Here are some examples of how these methods can be utilized:
|
||||||
|
|
||||||
|
- Extracting the email address (`jwt["sub"]`)
|
||||||
|
|
||||||
|
```dart
|
||||||
|
String jwt = "your.jwt.token";
|
||||||
|
final String? email = jwt.jwtEmail(); // Returns the email address in the JWT
|
||||||
|
```
|
||||||
|
|
||||||
|
- Extracting the token expiration time (`jwt["exp"]`)
|
||||||
|
|
||||||
|
```dart
|
||||||
|
String jwt = "your.jwt.token";
|
||||||
|
// Returns a `DateTime?` when the token expires
|
||||||
|
final DateTime? email = jwt.jwtExpiryTime();
|
||||||
|
```
|
||||||
|
|
||||||
|
- Extracting the user ID (`jwt["uid"]`)
|
||||||
|
|
||||||
|
```dart
|
||||||
|
String jwt = "your.jwt.token";
|
||||||
|
final String? uid = jwt.jwtUserId(); // Returns the UID value from the token
|
||||||
|
```
|
||||||
|
|
||||||
|
### String Utilities
|
||||||
|
|
||||||
|
The following utilities have been added to enhance working with `String`
|
||||||
|
objects:
|
||||||
|
|
||||||
|
- `isNullOrEmpty`: Returns `true` if a `String?` is either null or consists of
|
||||||
|
only whitespace.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
const String? nullString = null;
|
||||||
|
const String? emptyString = " ";
|
||||||
|
const String? nonEmptyString = "Hello World!";
|
||||||
|
|
||||||
|
print(nullString.isNullOrEmpty) // true
|
||||||
|
print(emptyString.isNullOrEmpty) // true
|
||||||
|
print(nonEmptyString.isNullOrEmpty) // false
|
||||||
|
```
|
||||||
|
|
||||||
|
- `isNotNullOrEmpty`: Returns `true` if a `String?` is neither null nor consists
|
||||||
|
of only whitespace.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
const String? nullString = null;
|
||||||
|
const String? emptyString = " ";
|
||||||
|
const String? nonEmptyString = "Hello World!";
|
||||||
|
|
||||||
|
print(nullString.isNotNullOrEmpty) // false
|
||||||
|
print(emptyString.isNotNullOrEmpty) // false
|
||||||
|
print(nonEmptyString.isNotNullOrEmpty) // true
|
||||||
|
```
|
||||||
|
|
||||||
|
- `splitByLength(int length)`: Splits a `String` into a `List<String>` where
|
||||||
|
each value is of the maximum length provided.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
const String text = "DartLang";
|
||||||
|
final List<String> result = text.splitByLength(3); // ["Dar", "tLa", "ng"]
|
||||||
|
```
|
||||||
|
|
||||||
|
- `capitalize`: Capitalizes the first letter of a given `String`
|
||||||
|
|
||||||
|
```dart
|
||||||
|
const String text = "hello";
|
||||||
|
final String capitalized = text.capitalize; // "Hello"
|
||||||
|
```
|
||||||
|
|
||||||
|
Additionally, the `CommonString` class provides a quick shortcut to common
|
||||||
|
strings, such as punctuation marks that are otherwise cumbersome to find or type.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! Feel free to fork the repository and submit pull
|
||||||
|
requests.
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
|
analyzer:
|
||||||
|
errors:
|
||||||
|
# treat missing required parameters as an error (not a hint)
|
||||||
|
missing_required_param: error
|
||||||
|
# treat missing returns as an error (not a hint)
|
||||||
|
missing_return: error
|
||||||
|
invalid_annotation_target: ignore
|
||||||
|
language:
|
||||||
|
strict-casts: true
|
||||||
|
|
||||||
|
linter:
|
||||||
|
rules:
|
||||||
|
always_declare_return_types: true
|
||||||
|
always_put_required_named_parameters_first: true
|
||||||
|
annotate_overrides: true
|
||||||
|
avoid_annotating_with_dynamic: true
|
||||||
|
avoid_dynamic_calls: true
|
||||||
|
avoid_escaping_inner_quotes: true
|
||||||
|
avoid_function_literals_in_foreach_calls: true
|
||||||
|
avoid_null_checks_in_equality_operators: true
|
||||||
|
avoid_print: true
|
||||||
|
avoid_relative_lib_imports: true
|
||||||
|
avoid_setters_without_getters: true
|
||||||
|
avoid_shadowing_type_parameters: true
|
||||||
|
avoid_single_cascade_in_expression_statements: true
|
||||||
|
avoid_unnecessary_containers: true
|
||||||
|
avoid_unused_constructor_parameters: true
|
||||||
|
avoid_void_async: true
|
||||||
|
camel_case_extensions: true
|
||||||
|
camel_case_types: true
|
||||||
|
cancel_subscriptions: true
|
||||||
|
close_sinks: true
|
||||||
|
collection_methods_unrelated_type: true
|
||||||
|
constant_identifier_names: true
|
||||||
|
control_flow_in_finally: true
|
||||||
|
depend_on_referenced_packages: true
|
||||||
|
directives_ordering: true
|
||||||
|
empty_constructor_bodies: true
|
||||||
|
empty_statements: true
|
||||||
|
eol_at_end_of_file: true
|
||||||
|
exhaustive_cases: true
|
||||||
|
file_names: true
|
||||||
|
flutter_style_todos: true
|
||||||
|
hash_and_equals: true
|
||||||
|
implementation_imports: true
|
||||||
|
implicit_call_tearoffs: true
|
||||||
|
leading_newlines_in_multiline_strings: true
|
||||||
|
missing_whitespace_between_adjacent_strings: true
|
||||||
|
no_adjacent_strings_in_list: true
|
||||||
|
no_duplicate_case_values: true
|
||||||
|
no_leading_underscores_for_library_prefixes: true
|
||||||
|
no_leading_underscores_for_local_identifiers: true
|
||||||
|
no_logic_in_create_state: true
|
||||||
|
no_runtimeType_toString: true
|
||||||
|
non_constant_identifier_names: true
|
||||||
|
null_check_on_nullable_type_parameter: true
|
||||||
|
null_closures: true
|
||||||
|
only_throw_errors: true
|
||||||
|
package_prefixed_library_names: true
|
||||||
|
prefer_adjacent_string_concatenation: true
|
||||||
|
prefer_asserts_in_initializer_lists: true
|
||||||
|
prefer_collection_literals: true
|
||||||
|
prefer_conditional_assignment: true
|
||||||
|
prefer_const_constructors_in_immutables: true
|
||||||
|
prefer_const_constructors: true
|
||||||
|
prefer_const_declarations: true
|
||||||
|
prefer_const_literals_to_create_immutables: true
|
||||||
|
prefer_constructors_over_static_methods: true
|
||||||
|
prefer_contains: true
|
||||||
|
prefer_double_quotes: true
|
||||||
|
prefer_final_fields: true
|
||||||
|
prefer_final_in_for_each: true
|
||||||
|
prefer_final_locals: true
|
||||||
|
prefer_for_elements_to_map_fromIterable: true
|
||||||
|
prefer_function_declarations_over_variables: true
|
||||||
|
prefer_generic_function_type_aliases: true
|
||||||
|
prefer_if_null_operators: true
|
||||||
|
prefer_initializing_formals: true
|
||||||
|
prefer_inlined_adds: true
|
||||||
|
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_null_aware_operators: true
|
||||||
|
prefer_spread_collections: true
|
||||||
|
prefer_typing_uninitialized_variables: true
|
||||||
|
provide_deprecation_message: true
|
||||||
|
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_pub_dependencies: true
|
||||||
|
type_init_formals: true
|
||||||
|
type_literal_in_constant_pattern: true
|
||||||
|
unawaited_futures: true
|
||||||
|
unnecessary_await_in_return: true
|
||||||
|
unnecessary_brace_in_string_interps: true
|
||||||
|
unnecessary_const: true
|
||||||
|
unnecessary_constructor_name: true
|
||||||
|
unnecessary_getters_setters: true
|
||||||
|
unnecessary_late: true
|
||||||
|
unnecessary_new: true
|
||||||
|
unnecessary_null_aware_assignments: true
|
||||||
|
unnecessary_null_in_if_null_operators: true
|
||||||
|
unnecessary_nullable_for_final_variable_declarations: true
|
||||||
|
unnecessary_overrides: true
|
||||||
|
unnecessary_parenthesis: true
|
||||||
|
unnecessary_statements: true
|
||||||
|
use_build_context_synchronously: true
|
||||||
|
use_colored_box: true
|
||||||
|
use_key_in_widget_constructors: true
|
||||||
|
valid_regexps: true
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
library arcane_helper_utils;
|
||||||
|
|
||||||
|
export "package:arcane_helper_utils/src/extensions/date_time.dart";
|
||||||
|
export "package:arcane_helper_utils/src/extensions/string.dart";
|
||||||
|
export "package:arcane_helper_utils/src/extensions/string_jwt.dart";
|
||||||
|
export "package:arcane_helper_utils/src/utils/ticker.dart";
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
import "package:week_number/iso.dart";
|
||||||
|
|
||||||
|
/// An extension on `DateTime` to get the start and end of various time periods.
|
||||||
|
extension StartAndEndOfPeriod on DateTime {
|
||||||
|
/// Returns a `DateTime` object representing the start of the hour.
|
||||||
|
///
|
||||||
|
/// The time is set to the beginning of the current hour with minutes, seconds,
|
||||||
|
/// and milliseconds set to zero.
|
||||||
|
DateTime get startOfHour => DateTime(year, month, day, hour);
|
||||||
|
|
||||||
|
/// Returns a `DateTime` object representing the end of the hour.
|
||||||
|
///
|
||||||
|
/// The time is set to the last microsecond of the current hour.
|
||||||
|
DateTime get endOfHour => DateTime(year, month, day, hour)
|
||||||
|
.add(const Duration(hours: 1))
|
||||||
|
.subtract(const Duration(microseconds: 1));
|
||||||
|
|
||||||
|
/// Returns a `DateTime` object representing the start of the day.
|
||||||
|
///
|
||||||
|
/// The time is set to 00:00 (midnight) of the current day.
|
||||||
|
DateTime get startOfDay => DateTime(year, month, day);
|
||||||
|
|
||||||
|
/// Returns a `DateTime` object representing the end of the day.
|
||||||
|
///
|
||||||
|
/// The time is set to the last microsecond of the current day, 23:59:59.999999.
|
||||||
|
DateTime get endOfDay => startOfDay
|
||||||
|
.add(const Duration(days: 1))
|
||||||
|
.subtract(const Duration(microseconds: 1));
|
||||||
|
|
||||||
|
/// Returns a `DateTime` object representing the end of the current week.
|
||||||
|
///
|
||||||
|
/// The time is set to the end of the last day of the current week (Sunday).
|
||||||
|
DateTime get endOfWeek => endOfDay.add(
|
||||||
|
Duration(
|
||||||
|
days: DateTime.daysPerWeek - weekday,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Returns a `DateTime` object representing the end of the current month.
|
||||||
|
///
|
||||||
|
/// The time is set to the last microsecond of the last day of the current month.
|
||||||
|
DateTime get endOfMonth => endOfDay.add(
|
||||||
|
Duration(
|
||||||
|
days: daysInMonth - day,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Returns a `DateTime` object representing the start of the current week.
|
||||||
|
///
|
||||||
|
/// The time is set to the start of the first day of the current week (Monday).
|
||||||
|
DateTime get startOfWeek => startOfDay.subtract(
|
||||||
|
Duration(
|
||||||
|
days: weekday - DateTime.monday,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Returns a `DateTime` object representing the start of the current month.
|
||||||
|
///
|
||||||
|
/// The time is set to the beginning of the first day of the current month.
|
||||||
|
DateTime get startOfMonth => DateTime(
|
||||||
|
year,
|
||||||
|
month,
|
||||||
|
1,
|
||||||
|
).startOfDay;
|
||||||
|
|
||||||
|
/// Returns a `DateTime` object representing the start of the current year.
|
||||||
|
///
|
||||||
|
/// The time is set to the beginning of the first day of the current year.
|
||||||
|
DateTime get startOfYear => DateTime(year).startOfDay;
|
||||||
|
|
||||||
|
/// Returns a `DateTime` object representing the end of the current year.
|
||||||
|
///
|
||||||
|
/// The time is set to the last microsecond of the last day of the current year.
|
||||||
|
DateTime get endOfYear => startOfYear
|
||||||
|
.add(
|
||||||
|
Duration(days: this.isLeapYear ? 365 : 364),
|
||||||
|
)
|
||||||
|
.endOfDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An extension on `DateTime` to get the number of days in the current month.
|
||||||
|
extension DaysInMonth on DateTime {
|
||||||
|
/// Returns the number of days in the current month.
|
||||||
|
///
|
||||||
|
/// It correctly handles leap years and different month lengths.
|
||||||
|
int get daysInMonth => DateTime(year, month + 1, 0).day;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An extension on `DateTime` to check if a date is today or if it is the same day as another date.
|
||||||
|
extension IsToday on DateTime {
|
||||||
|
/// Returns `true` if the current date is today.
|
||||||
|
bool get isToday => DateTime.now().difference(this).inDays == 0;
|
||||||
|
|
||||||
|
/// Returns `true` if the current date is the same day as [other].
|
||||||
|
bool isSameDayAs(DateTime other) =>
|
||||||
|
DateTime(other.year, other.month, other.day)
|
||||||
|
.isAtSameMomentAs(DateTime(year, month, day));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An extension on `DateTime` to get the first day of the current week.
|
||||||
|
extension FirstDayOfWeek on DateTime {
|
||||||
|
/// Returns a `DateTime` object representing the first day of the current week (Monday).
|
||||||
|
///
|
||||||
|
/// The time is set to the start of that day.
|
||||||
|
DateTime get firstDayOfWeek {
|
||||||
|
final int daysToSubtract = weekday - DateTime.monday;
|
||||||
|
final DateTime firstDay =
|
||||||
|
subtract(Duration(days: daysToSubtract)).startOfDay;
|
||||||
|
return firstDay;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/// Provides a quick shortcut to common strings, such as punctuation marks that are otherwise
|
||||||
|
/// cumbersome to find or type.
|
||||||
|
abstract class CommonString {
|
||||||
|
/// An em dash (`—`) is commonly used in typography to set off parenthetical
|
||||||
|
/// phrases or provide emphasis in a sentence.
|
||||||
|
static const String emDash = "—";
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Nullability on String? {
|
||||||
|
/// Returns `true` if the `String?` is neither `null` nor only contains whitespace.
|
||||||
|
bool get isNotNullOrEmpty => !isNullOrEmpty;
|
||||||
|
|
||||||
|
/// Returns `true` if the `String?` is either `null` or contains only whitespace.
|
||||||
|
bool get isNullOrEmpty => this == null || (this ?? "").trim().isEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An extension on `String` to split the string into parts of a specified length.
|
||||||
|
extension Split on String {
|
||||||
|
/// Splits the string into a list of substrings, each with a maximum length of [length].
|
||||||
|
///
|
||||||
|
/// This method divides the string into chunks of size [length]. If the string's
|
||||||
|
/// length is not a multiple of [length], the last chunk may be smaller than [length].
|
||||||
|
///
|
||||||
|
/// - [length]: The number of characters in each part.
|
||||||
|
///
|
||||||
|
/// Returns a list of substrings where each has a maximum of [length] characters.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```dart
|
||||||
|
/// String text = "DartLang";
|
||||||
|
/// List<String> result = text.splitByLength(3); // ["Dar", "tLa", "ng"]
|
||||||
|
/// ```
|
||||||
|
List<String> splitByLength(int length) {
|
||||||
|
final List<String> parts = [];
|
||||||
|
String string = this;
|
||||||
|
|
||||||
|
while (string.isNotEmpty) {
|
||||||
|
parts.add(string.substring(0, length));
|
||||||
|
string = string.substring(length);
|
||||||
|
}
|
||||||
|
return parts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An extension on `String` to perform text manipulation tasks.
|
||||||
|
extension TextManipulation on String {
|
||||||
|
/// Capitalizes the first letter of the string.
|
||||||
|
///
|
||||||
|
/// This method returns a new string where the first character is converted
|
||||||
|
/// to uppercase, while the rest of the string remains unchanged.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```dart
|
||||||
|
/// String text = "hello";
|
||||||
|
/// String capitalized = text.capitalize; // "Hello"
|
||||||
|
/// ```
|
||||||
|
String get capitalize {
|
||||||
|
if (isEmpty) return "";
|
||||||
|
return "${this[0].toUpperCase()}${substring(1)}";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
import "dart:convert";
|
||||||
|
|
||||||
|
/// An extension on `String` to extract useful information from JSON Web Tokens (JWT).
|
||||||
|
///
|
||||||
|
/// This extension provides methods to decode a JWT string and retrieve common
|
||||||
|
/// fields like email, expiration time, and user ID.
|
||||||
|
extension JWTUtility on String {
|
||||||
|
/// Extracts the email from the JWT payload.
|
||||||
|
///
|
||||||
|
/// This method attempts to parse the JWT and retrieve the `sub` field, which is
|
||||||
|
/// typically used to store the email of the token owner.
|
||||||
|
///
|
||||||
|
/// Returns the email as a `String` if present, or `null` if the parsing fails or the
|
||||||
|
/// email is not found.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```dart
|
||||||
|
/// String token = "your.jwt.token";
|
||||||
|
/// String? email = token.jwtEmail();
|
||||||
|
/// ```
|
||||||
|
String? jwtEmail() {
|
||||||
|
try {
|
||||||
|
final payload = _parseJwt(this);
|
||||||
|
final String email = payload["sub"] as String;
|
||||||
|
return email;
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the expiration time from the JWT payload.
|
||||||
|
///
|
||||||
|
/// This method retrieves the `exp` field from the JWT, which represents the expiration
|
||||||
|
/// time as a Unix timestamp. The timestamp is converted to a `DateTime` object.
|
||||||
|
///
|
||||||
|
/// Returns the `DateTime` representing the expiration time, or `null` if the parsing
|
||||||
|
/// fails or the expiration time is not found.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```dart
|
||||||
|
/// String token = "your.jwt.token";
|
||||||
|
/// DateTime? expiry = token.jwtExpiryTime();
|
||||||
|
/// ```
|
||||||
|
DateTime? jwtExpiryTime() {
|
||||||
|
try {
|
||||||
|
final payload = _parseJwt(this);
|
||||||
|
final expiry = payload["exp"] as int;
|
||||||
|
final date = DateTime.fromMillisecondsSinceEpoch(expiry * 1000);
|
||||||
|
return date;
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the user ID from the JWT payload.
|
||||||
|
///
|
||||||
|
/// This method retrieves the `uid` field, which is typically the unique user identifier.
|
||||||
|
/// This ID can be used in analytics or for tracking purposes.
|
||||||
|
///
|
||||||
|
/// Returns the user ID as a `String`, or `null` if the parsing fails or the ID is not found.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```dart
|
||||||
|
/// String token = "your.jwt.token";
|
||||||
|
/// String? userId = token.jwtUserId();
|
||||||
|
/// ```
|
||||||
|
String? jwtUserId() {
|
||||||
|
try {
|
||||||
|
final payload = _parseJwt(this);
|
||||||
|
final String id = payload["uid"] as String;
|
||||||
|
return id;
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decodes a base64 URL-encoded string.
|
||||||
|
///
|
||||||
|
/// This method replaces the URL-safe characters in the base64 string (`-` and `_`)
|
||||||
|
/// with standard base64 characters (`+` and `/`), then decodes the string into UTF-8.
|
||||||
|
///
|
||||||
|
/// Throws an `Exception` if the base64 string is not properly padded or is invalid.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```dart
|
||||||
|
/// String decoded = _decodeBase64("your_base64_string");
|
||||||
|
/// ```
|
||||||
|
String _decodeBase64(String str) {
|
||||||
|
String output = str.replaceAll("-", "+").replaceAll("_", "/");
|
||||||
|
switch (output.length % 4) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
output += "==";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
output += "=";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw Exception('Illegal base64url string!"');
|
||||||
|
}
|
||||||
|
|
||||||
|
return utf8.decode(base64Url.decode(output));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses the JWT and returns the payload as a map.
|
||||||
|
///
|
||||||
|
/// A JWT consists of three parts: header, payload, and signature, separated by dots (`.`).
|
||||||
|
/// This method decodes the payload (the second part) from base64 and converts it into
|
||||||
|
/// a `Map<String, dynamic>`.
|
||||||
|
///
|
||||||
|
/// Throws an `Exception` if the token is not valid or the payload is not a proper JSON map.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```dart
|
||||||
|
/// Map<String, dynamic> payload = _parseJwt("your.jwt.token");
|
||||||
|
/// ```
|
||||||
|
Map<String, dynamic> _parseJwt(String token) {
|
||||||
|
final parts = token.split(".");
|
||||||
|
if (parts.length != 3) {
|
||||||
|
throw Exception("invalid token");
|
||||||
|
}
|
||||||
|
|
||||||
|
final payload = _decodeBase64(parts[1]);
|
||||||
|
final dynamic payloadMap = json.decode(payload);
|
||||||
|
if (payloadMap is! Map<String, dynamic>) {
|
||||||
|
throw Exception("invalid payload");
|
||||||
|
}
|
||||||
|
|
||||||
|
return payloadMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
|
||||||
|
/// A `JsonConverter` that converts a nullable `String?` to a nullable `double?`.
|
||||||
|
///
|
||||||
|
/// This converter is useful for converting JSON strings to Dart `double?` values and vice versa,
|
||||||
|
/// especially when dealing with APIs or data sources where numbers might be represented as strings.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// Assuming a JSON string of `{"valueIsDouble": "123.456"}` is returned from
|
||||||
|
/// the API and you want to access the value from your class as:
|
||||||
|
/// ```dart
|
||||||
|
/// final double? myValue = MyFreezedClass.valueIsDouble;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// You would implement the converter as follows:
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// @freezed
|
||||||
|
/// class MyFreezedClass with _$MyFreezedClass {
|
||||||
|
/// const factory MyFreezedClass({
|
||||||
|
/// @DecimalConverter() double? valueIsDouble,
|
||||||
|
/// }) = _MyFreezedClass;
|
||||||
|
///
|
||||||
|
/// factory MyFreezedClass.fromJson(Map<String, dynamic> json) =>
|
||||||
|
/// _$MyFreezedClassFromJson(json);
|
||||||
|
///
|
||||||
|
/// const MyFreezedClass._();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
class DoubleConverter implements JsonConverter<double?, String?> {
|
||||||
|
/// Creates a const instance of [DoubleConverter].
|
||||||
|
const DoubleConverter();
|
||||||
|
|
||||||
|
/// Converts a nullable `String?` to a nullable `double?`.
|
||||||
|
///
|
||||||
|
/// If the input string is `null` or can't be parsed into a valid `double`,
|
||||||
|
/// this method returns `null`.
|
||||||
|
@override
|
||||||
|
double? fromJson(String? value) {
|
||||||
|
return double.tryParse(value ?? "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a nullable `double?` to a nullable `String?`.
|
||||||
|
///
|
||||||
|
/// If the input `double` is `null`, this method returns `null`.
|
||||||
|
@override
|
||||||
|
String? toJson(double? value) => value?.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `JsonConverter` that converts a nullable `String?` to a nullable `int?`.
|
||||||
|
///
|
||||||
|
/// This converter is useful for converting JSON strings to Dart `int?` values and vice versa,
|
||||||
|
/// especially when dealing with APIs or data sources where numbers might be represented as strings.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// Assuming a JSON string of `{"valueIsInt": "123"}` is returned from
|
||||||
|
/// the API and you want to access the value from your class as:
|
||||||
|
/// ```dart
|
||||||
|
/// final int? myValue = MyFreezedClass.valueIsInt;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// You would implement the converter as follows:
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// @freezed
|
||||||
|
/// class MyFreezedClass with _$MyFreezedClass {
|
||||||
|
/// const factory MyFreezedClass({
|
||||||
|
/// @IntegerConverter() double? valueIsInt,
|
||||||
|
/// }) = _MyFreezedClass;
|
||||||
|
///
|
||||||
|
/// factory MyFreezedClass.fromJson(Map<String, dynamic> json) =>
|
||||||
|
/// _$MyFreezedClassFromJson(json);
|
||||||
|
///
|
||||||
|
/// const MyFreezedClass._();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
class IntegerConverter implements JsonConverter<int?, String?> {
|
||||||
|
/// Creates a const instance of [IntegerConverter].
|
||||||
|
const IntegerConverter();
|
||||||
|
|
||||||
|
/// Converts a nullable `String?` to a nullable `int?`.
|
||||||
|
///
|
||||||
|
/// If the input string is `null` or can't be parsed into a valid `int`,
|
||||||
|
/// this method returns `null`.
|
||||||
|
@override
|
||||||
|
int? fromJson(String? value) {
|
||||||
|
return int.tryParse(value ?? "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a nullable `int?` to a nullable `String?`.
|
||||||
|
///
|
||||||
|
/// If the input `int` is `null`, this method returns `null`.
|
||||||
|
@override
|
||||||
|
String? toJson(int? value) => value?.toString();
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/// Creates a [Ticker] that emits a tick every [interval] seconds until the
|
||||||
|
/// [timeout] is reached.
|
||||||
|
///
|
||||||
|
/// Options:
|
||||||
|
/// - `timeout` (Duration) - The amount of time the ticker should run for
|
||||||
|
/// - `interval` (Duration, _optional_) - The amount of time between each tick.
|
||||||
|
/// Defaults to `Duration(seconds: 1)`.
|
||||||
|
///
|
||||||
|
/// Usage:
|
||||||
|
/// ```dart
|
||||||
|
/// final Stream<int> ticker = const Ticker().tick(
|
||||||
|
/// timeout: Duration(seconds: 30),
|
||||||
|
/// interval: Duration(seconds: 5)
|
||||||
|
/// );
|
||||||
|
///
|
||||||
|
/// await for (final int ticksRemaining in ticker) {
|
||||||
|
/// if (ticksRemaining == 0) print("Time's up!");
|
||||||
|
/// print('Tick! $ticksRemaining');
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
class Ticker {
|
||||||
|
const Ticker();
|
||||||
|
|
||||||
|
/// Starts the `Ticker`'s stream.
|
||||||
|
Stream<int> tick({
|
||||||
|
required Duration timeout,
|
||||||
|
Duration interval = const Duration(seconds: 1),
|
||||||
|
}) {
|
||||||
|
final int ticks = timeout.inSeconds ~/ interval.inSeconds;
|
||||||
|
return Stream.periodic(interval, (x) => ticks - x - 1).take(ticks);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
name: arcane_helper_utils
|
||||||
|
description: "A variety of utilities for Flutter and Dart"
|
||||||
|
version: 1.0.0
|
||||||
|
homepage: https://github.com/hanskokx/arcane_helper_utils
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: ^3.5.2
|
||||||
|
flutter: ">=1.17.0"
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
freezed_annotation: ^2.4.4
|
||||||
|
week_number: ^1.1.0
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
flutter_lints: ^4.0.0
|
||||||
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import "package:arcane_helper_utils/src/extensions/date_time.dart";
|
||||||
|
import "package:flutter_test/flutter_test.dart";
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group("[DateTime] StartAndEndOfPeriod", () {
|
||||||
|
test("Start of hour", () {
|
||||||
|
final DateTime startOfHour = DateTime(2000, 1, 1, 12, 36, 53).startOfHour;
|
||||||
|
expect(startOfHour, equals(DateTime(2000, 1, 1, 12, 0, 0)));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("End of hour", () {
|
||||||
|
final DateTime endOfHour = DateTime(2000, 1, 1, 12, 36, 53).endOfHour;
|
||||||
|
expect(endOfHour, equals(DateTime(2000, 1, 1, 12, 59, 59, 999, 999)));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Start of day", () {
|
||||||
|
final DateTime startOfDay = DateTime(2000, 1, 1, 12, 36, 53).startOfDay;
|
||||||
|
expect(startOfDay, equals(DateTime(2000, 1, 1, 0, 0, 0)));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("End of day", () {
|
||||||
|
final DateTime endOfDay = DateTime(2000, 1, 1, 12, 36, 53).endOfDay;
|
||||||
|
expect(endOfDay, equals(DateTime(2000, 1, 1, 23, 59, 59, 999, 999)));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Start of week", () {
|
||||||
|
final DateTime startOfWeek = DateTime(2000, 1, 1, 12, 36, 53).startOfWeek;
|
||||||
|
expect(startOfWeek, equals(DateTime(1999, 12, 27, 0, 0, 0)));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("End of week", () {
|
||||||
|
final DateTime endOfWeek = DateTime(2000, 1, 1, 12, 36, 53).endOfWeek;
|
||||||
|
expect(endOfWeek, equals(DateTime(2000, 1, 2, 23, 59, 59, 999, 999)));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Start of month", () {
|
||||||
|
final DateTime startOfMonth =
|
||||||
|
DateTime(2000, 1, 17, 12, 36, 53).startOfMonth;
|
||||||
|
expect(startOfMonth, equals(DateTime(2000, 1, 1, 0, 0, 0)));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("End of month", () {
|
||||||
|
final DateTime endOfMonth = DateTime(2000, 1, 17, 12, 36, 53).endOfMonth;
|
||||||
|
expect(endOfMonth, equals(DateTime(2000, 1, 31, 23, 59, 59, 999, 999)));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("End of month (leap year)", () {
|
||||||
|
final DateTime endOfMonth = DateTime(2024, 2, 17, 12, 36, 53).endOfMonth;
|
||||||
|
expect(endOfMonth, equals(DateTime(2024, 2, 29, 23, 59, 59, 999, 999)));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Start of year", () {
|
||||||
|
final DateTime startOfYear =
|
||||||
|
DateTime(2000, 5, 17, 12, 36, 53).startOfYear;
|
||||||
|
expect(startOfYear, equals(DateTime(2000, 1, 1, 0, 0, 0)));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("End of year", () {
|
||||||
|
final DateTime endOfYear = DateTime(2000, 4, 17, 12, 36, 53).endOfYear;
|
||||||
|
expect(endOfYear, equals(DateTime(2000, 12, 31, 23, 59, 59, 999, 999)));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("End of year (leap year)", () {
|
||||||
|
final DateTime endOfYear = DateTime(2024, 4, 17, 12, 36, 53).endOfYear;
|
||||||
|
expect(endOfYear, equals(DateTime(2024, 12, 31, 23, 59, 59, 999, 999)));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("First day of week", () {
|
||||||
|
final DateTime firstDayOfWeek =
|
||||||
|
DateTime(2024, 4, 17, 12, 36, 53).firstDayOfWeek;
|
||||||
|
expect(
|
||||||
|
firstDayOfWeek,
|
||||||
|
equals(DateTime(2024, 4, 15)),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
group("[DateTime] Calculations", () {
|
||||||
|
test("Is today", () {
|
||||||
|
final bool isToday = DateTime.now().isToday;
|
||||||
|
final bool isNotToday =
|
||||||
|
DateTime.now().subtract(const Duration(days: 1)).isToday;
|
||||||
|
expect(isToday, equals(true));
|
||||||
|
expect(isNotToday, equals(false));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Is same day as", () {
|
||||||
|
final DateTime first = DateTime(2000, 1, 1);
|
||||||
|
final DateTime second = DateTime(2000, 1, 2);
|
||||||
|
final DateTime third = DateTime(2000, 1, 1);
|
||||||
|
final bool firstAndSecond = first.isSameDayAs(second);
|
||||||
|
final bool firstAndThird = first.isSameDayAs(third);
|
||||||
|
|
||||||
|
expect(firstAndSecond, equals(false));
|
||||||
|
expect(firstAndThird, equals(true));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user