mirror of
https://github.com/acamarata/pray-calc-dart.git
synced 2026-06-30 19:04:25 +00:00
docs: update README, add wiki docs, and document types (P1)
This commit is contained in:
parent
882c586e2f
commit
fc01b129f4
7 changed files with 234 additions and 47 deletions
34
.github/wiki/CODE_OF_CONDUCT.md
vendored
Normal file
34
.github/wiki/CODE_OF_CONDUCT.md
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as contributors and maintainers pledge to make participation in this project a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment:
|
||||
|
||||
- Using welcoming and inclusive language
|
||||
- Being respectful of differing viewpoints and experiences
|
||||
- Accepting constructive criticism gracefully
|
||||
- Focusing on what is best for the community
|
||||
- Showing empathy toward other community members
|
||||
|
||||
Examples of unacceptable behavior:
|
||||
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information without explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior. They will take appropriate and fair corrective action in response to any behavior they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project maintainer at alisalaah@gmail.com. All complaints will be reviewed and investigated. The project team is obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
|
||||
28
.github/wiki/SECURITY.md
vendored
Normal file
28
.github/wiki/SECURITY.md
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# Security
|
||||
|
||||
## Scope
|
||||
|
||||
`pray_calc_dart` is a pure-math library with no network access, no file I/O, and no external dependencies beyond `nrel_spa`. The attack surface is limited to the mathematical functions themselves.
|
||||
|
||||
The main concern is input validation: functions accept latitude (-90 to 90), longitude (-180 to 180), and UTC offset. Out-of-range values produce undefined behavior — clamp inputs to valid ranges before passing untrusted data.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you discover a security issue (for example, a case where malformed input causes unexpected behavior or crashes), please report it privately before filing a public issue.
|
||||
|
||||
**Contact:** alisalaah@gmail.com
|
||||
|
||||
Include:
|
||||
|
||||
1. A description of the vulnerability
|
||||
2. Steps to reproduce it
|
||||
3. The version of `pray_calc_dart` where you observed the issue
|
||||
4. Any suggested fix if you have one
|
||||
|
||||
You can expect an acknowledgment within 48 hours and a resolution or status update within 7 days.
|
||||
|
||||
## Known Limitations
|
||||
|
||||
- Prayer times are computed using the NREL Solar Position Algorithm. Accuracy is approximately one second relative to the reference implementation. Results near polar latitudes (above 65 degrees N/S) should be treated as estimates.
|
||||
- The MCW seasonal model uses empirical piecewise-linear functions. Accuracy at extreme latitudes degrades gracefully rather than producing errors, but times may differ from local observation.
|
||||
- Time zone handling is the caller's responsibility. The library accepts a UTC offset in hours and returns fractional hours in that offset. DST adjustments must be applied by the caller.
|
||||
3
.github/wiki/_Footer.md
vendored
Normal file
3
.github/wiki/_Footer.md
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[](https://pub.dev/packages/pray_calc_dart) [](https://github.com/acamarata/pray-calc-dart/blob/main/LICENSE)
|
||||
|
||||
[pub.dev](https://pub.dev/packages/pray_calc_dart) | [GitHub](https://github.com/acamarata/pray-calc-dart) | [Issues](https://github.com/acamarata/pray-calc-dart/issues)
|
||||
20
.github/wiki/_Sidebar.md
vendored
Normal file
20
.github/wiki/_Sidebar.md
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
## pray_calc_dart
|
||||
|
||||
- [Home](Home)
|
||||
- [API Reference](API-Reference)
|
||||
|
||||
**Guides**
|
||||
- [Quickstart](guides/quickstart)
|
||||
- [Advanced Usage](guides/advanced)
|
||||
|
||||
**Examples**
|
||||
- [Basic Usage](examples/basic-usage)
|
||||
- [Flutter Integration](examples/flutter-integration)
|
||||
|
||||
**Project**
|
||||
- [Code of Conduct](CODE_OF_CONDUCT)
|
||||
- [Security](SECURITY)
|
||||
|
||||
---
|
||||
|
||||
[pub.dev](https://pub.dev/packages/pray_calc_dart) | [GitHub](https://github.com/acamarata/pray-calc-dart)
|
||||
122
.github/wiki/examples/flutter-integration.md
vendored
Normal file
122
.github/wiki/examples/flutter-integration.md
vendored
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
# Flutter Integration
|
||||
|
||||
This example shows how to use `pray_calc_dart` in a Flutter widget. It reads the device's current location using `geolocator` and displays the current prayer times for that location.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Add to `pubspec.yaml`:
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
pray_calc_dart: ^1.0.0
|
||||
geolocator: ^14.0.0
|
||||
```
|
||||
|
||||
## PrayerTimesCard Widget
|
||||
|
||||
```dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:pray_calc_dart/pray_calc_dart.dart';
|
||||
|
||||
class PrayerTimesCard extends StatefulWidget {
|
||||
const PrayerTimesCard({super.key});
|
||||
|
||||
@override
|
||||
State<PrayerTimesCard> createState() => _PrayerTimesCardState();
|
||||
}
|
||||
|
||||
class _PrayerTimesCardState extends State<PrayerTimesCard> {
|
||||
PrayerTimes? _times;
|
||||
String? _error;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadTimes();
|
||||
}
|
||||
|
||||
Future<void> _loadTimes() async {
|
||||
try {
|
||||
final permission = await Geolocator.requestPermission();
|
||||
if (permission == LocationPermission.denied ||
|
||||
permission == LocationPermission.deniedForever) {
|
||||
setState(() => _error = 'Location permission denied.');
|
||||
return;
|
||||
}
|
||||
|
||||
final pos = await Geolocator.getCurrentPosition();
|
||||
|
||||
// UTC offset in hours — derive from the device's local time.
|
||||
final utcOffset =
|
||||
DateTime.now().timeZoneOffset.inMinutes / 60.0;
|
||||
|
||||
final times = getTimes(
|
||||
DateTime.now(),
|
||||
pos.latitude,
|
||||
pos.longitude,
|
||||
utcOffset,
|
||||
);
|
||||
|
||||
setState(() => _times = times);
|
||||
} catch (e) {
|
||||
setState(() => _error = e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_error != null) {
|
||||
return Text('Error: $_error');
|
||||
}
|
||||
if (_times == null) {
|
||||
return const CircularProgressIndicator();
|
||||
}
|
||||
|
||||
final rows = [
|
||||
('Fajr', _times!.fajr),
|
||||
('Sunrise', _times!.sunrise),
|
||||
('Dhuhr', _times!.dhuhr),
|
||||
('Asr', _times!.asr),
|
||||
('Maghrib', _times!.maghrib),
|
||||
('Isha', _times!.isha),
|
||||
('Qiyam', _times!.qiyam),
|
||||
];
|
||||
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: rows.map((r) {
|
||||
final (name, hours) = r;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 2),
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 80,
|
||||
child: Text(
|
||||
name,
|
||||
style: const TextStyle(fontWeight: FontWeight.w600),
|
||||
),
|
||||
),
|
||||
Text(formatTime(hours)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `getTimes` is a pure synchronous function. Only the location request is async.
|
||||
- Pass `hanafi: true` to `getTimes` for the Hanafi Asr convention (shadow factor 2 instead of 1).
|
||||
- `formatTime` returns `'N/A'` for unreachable events (polar nights). Handle this in the UI if targeting high-latitude users.
|
||||
- For production use, cache the result and re-compute once per day or on location change. Prayer times change by only a few minutes per day at most latitudes.
|
||||
57
README.md
57
README.md
|
|
@ -3,6 +3,7 @@
|
|||
[](https://pub.dev/packages/pray_calc_dart)
|
||||
[](https://github.com/acamarata/pray-calc-dart/actions/workflows/ci.yml)
|
||||
[](LICENSE)
|
||||
[](https://github.com/acamarata/pray-calc-dart/wiki)
|
||||
|
||||
Islamic prayer times for Dart and Flutter. Pure Dart port of [pray-calc](https://github.com/acamarata/pray-calc), implementing the MCW seasonal model and dynamic twilight angles. Uses [nrel_spa](https://github.com/acamarata/nrel-spa-dart) for the NREL Solar Position Algorithm.
|
||||
|
||||
|
|
@ -34,61 +35,23 @@ void main() {
|
|||
|
||||
## API
|
||||
|
||||
### `getTimes(date, lat, lng, tz, {elevation, temperature, pressure, hanafi})`
|
||||
Full API documentation, guides, and examples are in the [wiki](https://github.com/acamarata/pray-calc-dart/wiki).
|
||||
|
||||
Computes all prayer times for a given date and location.
|
||||
### Core functions
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `date` | `DateTime` | required | Local date (time-of-day ignored) |
|
||||
| `lat` | `double` | required | Latitude (-90 to 90, south negative) |
|
||||
| `lng` | `double` | required | Longitude (-180 to 180, west negative) |
|
||||
| `tz` | `double` | required | UTC offset in hours (e.g., -5 for EST) |
|
||||
| `elevation` | `double` | 0 | Observer elevation in meters |
|
||||
| `temperature` | `double` | 15 | Ambient temperature in Celsius |
|
||||
| `pressure` | `double` | 1013.25 | Atmospheric pressure in mbar |
|
||||
| `hanafi` | `bool` | false | Hanafi Asr (2x shadow) vs Shafi'i (1x) |
|
||||
|
||||
Returns a `PrayerTimes` object with fractional-hour values for: `qiyam`, `fajr`, `sunrise`, `noon`, `dhuhr`, `asr`, `maghrib`, `isha`, and the computed `angles`.
|
||||
|
||||
### `getAngles(date, lat, lng, {elevation, temperature, pressure})`
|
||||
|
||||
Computes dynamic twilight depression angles using the three-layer model:
|
||||
|
||||
1. MCW seasonal base (piecewise-linear, latitude-dependent)
|
||||
2. Ephemeris corrections (Earth-Sun distance, Fourier season smoothing)
|
||||
3. Environmental corrections (elevation dip, atmospheric refraction)
|
||||
|
||||
Returns `TwilightAngles` with `fajrAngle` and `ishaAngle` in degrees, clipped to [10, 22].
|
||||
|
||||
### `getSpa(date, lat, lng, tz, {...})`
|
||||
|
||||
Full NREL Solar Position Algorithm. Accurate to +/-0.0003 degrees for zenith angle. Supports custom zenith angles for twilight calculations.
|
||||
|
||||
### `formatTime(hours)`
|
||||
|
||||
Converts fractional hours to an `HH:MM:SS` string. Returns `"N/A"` for non-finite values.
|
||||
|
||||
### Additional Functions
|
||||
|
||||
- `solarEphemeris(jd)` -- Jean Meeus Ch. 25 low-precision ephemeris
|
||||
- `toJulianDate(date)` -- DateTime to Julian Date
|
||||
- `getAsr(solarNoon, latitude, declination, {hanafi})` -- Asr computation
|
||||
- `getQiyam(fajrTime, ishaTime)` -- Last third of the night
|
||||
- `getMscFajr(date, latitude)` -- MCW Fajr offset in minutes
|
||||
- `getMscIsha(date, latitude, [shafaq])` -- MCW Isha offset in minutes
|
||||
- `minutesToDepression(minutes, latDeg, declDeg)` -- Time to angle conversion
|
||||
| Function | Description |
|
||||
| --- | --- |
|
||||
| `getTimes(date, lat, lng, tz, {...})` | All prayer times for a date and location |
|
||||
| `getAngles(date, lat, lng, {...})` | Dynamic Fajr/Isha depression angles |
|
||||
| `getSpa(date, lat, lng, tz, {...})` | NREL Solar Position Algorithm (re-export) |
|
||||
| `formatTime(hours)` | Fractional hours to `HH:MM:SS` string |
|
||||
|
||||
## Dynamic Angle Algorithm
|
||||
|
||||
Fixed-angle methods (ISNA 15 degrees, MWL 18 degrees, etc.) produce inaccurate Fajr times at latitudes above 45 degrees N/S. The dynamic method adapts the depression angle based on season, latitude, Earth-Sun distance, and local atmospheric conditions.
|
||||
Fixed-angle methods (ISNA 15 degrees, MWL 18 degrees) produce inaccurate Fajr times at latitudes above 45 degrees N/S. The dynamic method adapts the depression angle based on season, latitude, Earth-Sun distance, and local atmospheric conditions.
|
||||
|
||||
Result: approximately 18 degrees at the equator, approximately 12-14 degrees at 50-55 degrees N in summer. Matches observational data from the Moonsighting Committee Worldwide.
|
||||
|
||||
## Architecture
|
||||
|
||||
Built in three layers: (1) [nrel_spa](https://pub.dev/packages/nrel_spa) provides the solar ephemeris foundation; (2) the MSC piecewise model computes seasonal minute offsets which are converted to depression angles via spherical trigonometry; (3) physics corrections (Earth-Sun distance, refraction, elevation dip) adjust the angle within [10°, 22°] bounds.
|
||||
|
||||
## Compatibility
|
||||
|
||||
Dart SDK 3.7.0+. Works in Flutter (iOS, Android, Web, Desktop), Dart CLI, and server-side Dart. Single dependency: [nrel_spa](https://pub.dev/packages/nrel_spa).
|
||||
|
|
|
|||
|
|
@ -62,14 +62,31 @@ class PrayerTimes {
|
|||
|
||||
/// Prayer times formatted as HH:MM:SS strings.
|
||||
class FormattedPrayerTimes {
|
||||
/// Start of the last third of the night (Qiyam al-Layl), as HH:MM:SS.
|
||||
final String qiyam;
|
||||
|
||||
/// True dawn (Subh Sadiq), as HH:MM:SS.
|
||||
final String fajr;
|
||||
|
||||
/// Astronomical sunrise, as HH:MM:SS.
|
||||
final String sunrise;
|
||||
|
||||
/// Solar noon (exact geometric transit), as HH:MM:SS.
|
||||
final String noon;
|
||||
|
||||
/// Dhuhr (2.5 minutes after solar noon), as HH:MM:SS.
|
||||
final String dhuhr;
|
||||
|
||||
/// Asr (Shafi'i or Hanafi shadow convention), as HH:MM:SS.
|
||||
final String asr;
|
||||
|
||||
/// Maghrib (sunset), as HH:MM:SS.
|
||||
final String maghrib;
|
||||
|
||||
/// Isha (nightfall, end of shafaq), as HH:MM:SS.
|
||||
final String isha;
|
||||
|
||||
/// Dynamic twilight angles used for this calculation.
|
||||
final TwilightAngles angles;
|
||||
|
||||
const FormattedPrayerTimes({
|
||||
|
|
|
|||
Loading…
Reference in a new issue