commit
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
node_modules
|
||||
.vscode
|
||||
dist
|
||||
flatpak/.flatpak-builder
|
||||
flatpak/build
|
||||
ressources/quran/downloads
|
||||
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 DarkBlackChocolate
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
264
README.md
Normal file
@@ -0,0 +1,264 @@
|
||||
# Muezzin
|
||||
|
||||
<!-- PROJECT LOGO -->
|
||||
<br />
|
||||
<div align="center">
|
||||
<a href="https://github.com/DBChoco/MuezzinPrayerTimes">
|
||||
<img src="ressources/images/icon.png" alt="Logo" width="150" height="150">
|
||||
</a>
|
||||
|
||||
<h3 align="center">Muezzin - مؤذن</h3>
|
||||
|
||||
<p align="center">
|
||||
A prayer times and Adhan application for Windows, macOS and GNU/Linux
|
||||
<br />
|
||||
<a href="https://github.com/DBChoco/MuezzinPrayerTimes/releases/latest"><strong>Download »</strong></a>
|
||||
<br />
|
||||
<br />
|
||||
<a href="https://github.com/DBChoco/MuezzinPrayerTimes">View Demo</a>
|
||||
·
|
||||
<a href="https://github.com/DBChoco/MuezzinPrayerTimes/issues">Report Bug</a>
|
||||
·
|
||||
<a href="https://github.com/DBChoco/MuezzinPrayerTimes/issues">Request Feature</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/DBChoco/Muezzin/graphs/contributors" alt="Contributors">
|
||||
<img src="https://img.shields.io/github/contributors/DBChoco/Muezzin" />
|
||||
</a>
|
||||
<a href="https://github.com/DBChoco/Muezzin/pulse" alt="Activity">
|
||||
<img src="https://img.shields.io/github/commit-activity/m/DBChoco/Muezzin" />
|
||||
</a>
|
||||
<a href="https://github.com/DBChoco/Muezzin" alt="Activity">
|
||||
<img src="https://img.shields.io/github/stars/DBChoco/Muezzin.svg" />
|
||||
</a>
|
||||
<a href="https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2FDBChoco" alt="Activity">
|
||||
<img src="https://img.shields.io/github/followers/DBChoco.svg?style=social&label=Follow&maxAge=2592000" />
|
||||
</a>
|
||||
<a href="https://www.reddit.com/r/Muezzin/" alt="Reddit">
|
||||
<img src="https://aleen42.github.io/badges/src/reddit.svg" />
|
||||
</a>
|
||||
|
||||
<br>
|
||||
|
||||
<a href="https://github.com/DBChoco/Muezzin" alt="Activity">
|
||||
<img src="https://img.shields.io/github/release/DBChoco/Muezzin.svg" />
|
||||
</a>
|
||||
<a href="https://aur.archlinux.org/packages/muezzin-bin" alt="AUR">
|
||||
<img src="https://img.shields.io/aur/version/muezzin-bin" />
|
||||
</a>
|
||||
<a href="https://snapcraft.io/muezzin">
|
||||
<img alt="muezzin" src="https://snapcraft.io/muezzin/badge.svg" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<a href='https://flathub.org/apps/details/io.github.dbchoco.muezzin'><img width='240' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-en.png'/></a>
|
||||
|
||||
<a href="https://snapcraft.io/muezzin">
|
||||
<img alt="Get it from the Snap Store" src="https://snapcraft.io/static/images/badges/en/snap-store-black.svg" />
|
||||
</a>
|
||||
|
||||
<!-- TABLE OF CONTENTS -->
|
||||
## Table of Contents
|
||||
|
||||
|
||||
<ul>
|
||||
<li><a href="#muezzin">Muezzin</a>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#about-the-project">About The Project</a>
|
||||
<ul>
|
||||
<li><a href="#supported-languages">Supported Languages</a></li>
|
||||
<li><a href="#built-with">Built With</a></li>
|
||||
<li><a href="#roadmap">Roadmap</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#how-to-install">How To Install</a>
|
||||
<ul>
|
||||
<li><a href="#windows">Windows</a></li>
|
||||
<li><a href="#macos">macOS</a></li>
|
||||
<li><a href="#gnulinux">GNU/Linux</a>
|
||||
<ul>
|
||||
<li><a href="#global">Global</a></li>
|
||||
<li><a href="#arch-based-distributions">Arch based distributions</a></li>
|
||||
<li><a href="#debian-based-distributions">Debian based distributions</a></li>
|
||||
<li><a href="#others">Others</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#contributing">Contributing</a></li>
|
||||
<li><a href="#license">License</a></li>
|
||||
<li><a href="#contact">Contact</a></li>
|
||||
<li><a href="#acknowledgments">Acknowledgments</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- ABOUT THE PROJECT -->
|
||||
## About The Project
|
||||
|
||||
<div align="center">
|
||||
<img src="screenshots/darkMode.png" alt="screenshot1" width="70%">
|
||||
</div>
|
||||
|
||||
We may all be familiar with Muslim Pro on our smartphones, but as someone who doesn't use my phone much, I wanted an app to help me keep track of prayer times without having to go on my smartphone, I wanted an app that was highly customizable and would let me choose <strong> my own </strong> Adhan and theme. And Alhamdoulillah after a few weeks of hard work, I did just that.
|
||||
|
||||
On Muezzin you can choose to play an Adhan or not, you can import your own audio file; you can also chose to have a background or not, and import your own.
|
||||
Currently we support 10 languages (and growing), and if you want us to add one more, you can submit a report <a href="https://github.com/DBChoco/MuezzinPrayerTimes/issues">here</a>
|
||||
|
||||
<div align="center">
|
||||
<img src="screenshots/settingsDark.png" alt="screenshot1" width="70%">
|
||||
</div>
|
||||
|
||||
The app also contains a Qur'an reader that is able to translations and transliterations. It supports many languages and you can expect many improvements in the future inshaAllah.
|
||||
|
||||
|
||||
<div align="center">
|
||||
<img src="screenshots/quranDark.png" alt="screenshot1" width="70%">
|
||||
</div>
|
||||
|
||||
|
||||
<!-- SUPPORTED LANGUAGES -->
|
||||
### Supported Languages
|
||||
* English
|
||||
* Français
|
||||
* Español
|
||||
* Italiano
|
||||
* Arabic
|
||||
* Deutsch
|
||||
* Nederlands
|
||||
* Norks
|
||||
* Svenska
|
||||
* Dansk
|
||||
* Urdu
|
||||
* Turkish (thanks @emrergin)
|
||||
|
||||
### Built With
|
||||
|
||||
* [Electron](https://www.electronjs.org/)
|
||||
* [Bootstrap](https://getbootstrap.com)
|
||||
* [Bootstrap-dark-5](https://vinorodrigues.github.io/bootstrap-dark-5/)
|
||||
* [adhan-js](https://github.com/batoulapps/adhan-js)
|
||||
* [FontAwesome](https://fontawesome.com/)
|
||||
* [Moment & Moment-timezone](https://momentjs.com/)
|
||||
* [Quran.com API](https://quran.api-docs.io)
|
||||
* Many electron modules
|
||||
|
||||
<!-- ROADMAP -->
|
||||
### Roadmap
|
||||
|
||||
- [x] Add Qur'an reading page
|
||||
- [ ] Improve the Qur'an page
|
||||
- [ ] Add mosque mode (improved visibility from afar & delays to prayers) (delayed)
|
||||
- [ ] Mosque interface with delays
|
||||
- [ ] Manual times
|
||||
- [ ] Custom text
|
||||
- [ ] Add Tasbih
|
||||
- [ ] Add weather widget
|
||||
- [x] Add icons to settings
|
||||
- [ ] Multi-language Support
|
||||
- [ ] Turkish
|
||||
|
||||
See the [open issues](https://github.com/DBChoco/MuezzinPrayerTimes/issues) for a full list of proposed features (and known issues).
|
||||
|
||||
<p align="right">(<a href="#muezzin">back to top</a>)</p>
|
||||
|
||||
<!-- How to install -->
|
||||
## How to install
|
||||
|
||||
### Windows
|
||||
From the <a href="https://github.com/DBChoco/MuezzinPrayerTimes/releases/latest"><strong>download page</strong></a>, select the .EXE installer.
|
||||
Download it and install it.
|
||||
|
||||
You might receive a warning, that is because the app is not signed and I do not have the money to do so. The app is completely safe, you can read through the source code or have a trusted friend do it for you, all the code is <b>Open-Source</b>.
|
||||
|
||||
### macOS
|
||||
From the <a href="https://github.com/DBChoco/MuezzinPrayerTimes/releases/latest"><strong>download page</strong></a>, select the .DMG installer.
|
||||
Download it and install it.
|
||||
|
||||
Same problem as the Windows installer
|
||||
> You might receive a warning, that is because the app is not signed and I do not have the money to do so. The app is completely safe, you can read through the source code or have a trusted friend do it for you, all the code is <b>Open-Source</b>.
|
||||
|
||||
### GNU/Linux
|
||||
|
||||
### Global
|
||||
|
||||
<a href='https://flathub.org/apps/details/io.github.dbchoco.muezzin'><img width='240' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-en.png'/></a>
|
||||
|
||||
<a href="https://snapcraft.io/muezzin">
|
||||
<img alt="Get it from the Snap Store" src="https://snapcraft.io/static/images/badges/en/snap-store-black.svg" />
|
||||
</a>
|
||||
|
||||
#### Arch based distributions
|
||||
You can either:
|
||||
<ul>
|
||||
<li><a href="https://github.com/DBChoco/MuezzinPrayerTimes/releases/latest"><strong>Download the .PACMAN file</strong></a> and install it through your favorite package manager</li>
|
||||
<li>Install it thorugh the AUR package <a href="https://aur.archlinux.org/packages/muezzin-bin"><strong>muezzin-bin</strong></a> with
|
||||
</li>
|
||||
|
||||
`yay -S muezzin-bin`
|
||||
|
||||
</ul>
|
||||
|
||||
#### Debian based distributions
|
||||
You can download the <a href="https://github.com/DBChoco/MuezzinPrayerTimes/releases/latest"><strong>Download the .DEB file</strong></a> and install it through your favorite package manager
|
||||
|
||||
`sudo apt install path/to/file.deb`
|
||||
|
||||
#### Others
|
||||
For other distributions, on the <a href="https://github.com/DBChoco/MuezzinPrayerTimes/releases/latest"><strong>download page</strong></a> you can choose from:
|
||||
<ul>
|
||||
<li>The .APPIMAGE file, which you can run on any Linux distribution and add to your autorun script</li>
|
||||
<li>The .TAR.GZ file, which you can unarchive wherever you want and launch via the terminal</li>
|
||||
</ul>
|
||||
|
||||
<p align="right">(<a href="#muezzin">back to top</a>)</p>
|
||||
|
||||
<!-- CONTRIBUTING -->
|
||||
## Contributing
|
||||
|
||||
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
|
||||
|
||||
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".
|
||||
|
||||
If you noticed a translation error or want to add a language yourself, feel free to contact me!
|
||||
|
||||
**Don't forget to give the project a star! Thanks again!**
|
||||
|
||||
<p align="right">(<a href="#muezzin">back to top</a>)</p>
|
||||
|
||||
|
||||
<!-- LICENSE -->
|
||||
## License
|
||||
|
||||
Distributed under the MIT License. See `LICENSE.txt` for more information.
|
||||
|
||||
|
||||
<!-- CONTACT -->
|
||||
## Contact
|
||||
|
||||
Project Link: [https://github.com/DBChoco/Muezzin](https://github.com/your_username/repo_name)
|
||||
|
||||
Discord: [Official Discord server](https://discord.gg/cpF9TTstN5)
|
||||
|
||||
<!-- ACKNOWLEDGMENTS -->
|
||||
## Acknowledgments
|
||||
|
||||
* [Source of images](https://unsplash.com/)
|
||||
* [Source of Mecca Adhan](https://www.youtube.com/watch?v=MaEzj5eRmjc&t)
|
||||
* [Source of al-Aqsa Adhan](https://www.youtube.com/watch?v=z2xEwSi2vaI)
|
||||
* [Source of Bismillah startup sound](https://www.youtube.com/c/FatihSeferagic/featured)
|
||||
* [Inspiration for logo](https://www.youtube.com/watch?v=oM5hNuAmWs0)
|
||||
* [Template for the README page](https://github.com/othneildrew/Best-README-Template)
|
||||
* [Source of Arabic fonts](https://github.com/fawazahmed0/quran-api)
|
||||
* Thanks to a few of my friends for helping me translate Muezzin and build it for macOS
|
||||
|
||||
### Source of images
|
||||
* [Light mode background image](https://unsplash.com/photos/njEXjDmYn8w)
|
||||
* [Dark mode background image](https://unsplash.com/photos/TAfqq1B3-2s)
|
||||
|
||||
<p align="right">(<a href="#muezzin">back to top</a>)</p>
|
||||
1
_config.yml
Normal file
@@ -0,0 +1 @@
|
||||
theme: jekyll-theme-cayman
|
||||
2014
flatpak/flatpak-node-generator.py
Normal file
15118
flatpak/generated-sources.json
Normal file
10
flatpak/io.github.dbchoco.muezzin.desktop
Normal file
@@ -0,0 +1,10 @@
|
||||
[Desktop Entry]
|
||||
Name=Muezzin
|
||||
Exec=muezzin-run
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Icon=io.github.dbchoco.muezzin
|
||||
StartupWMClass=Muezzin
|
||||
Comment=Islamic prayer times app
|
||||
MimeType=x-scheme-handler/muezzin;
|
||||
Categories=Utility;
|
||||
55
flatpak/io.github.dbchoco.muezzin.metainfo.xml
Normal file
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>io.github.dbchoco.muezzin</id>
|
||||
|
||||
<name>Muezzin</name>
|
||||
<summary>Islamic prayer times application</summary>
|
||||
<url type="homepage">https://github.com/DBChoco/Muezzin</url>
|
||||
<url type="bugtracker">https://github.com/DBChoco/Muezzin/issues</url>
|
||||
<url type="contact">https://www.reddit.com/r/Muezzin/</url>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>MIT</project_license>
|
||||
<description>
|
||||
<p>
|
||||
Islamic prayer times (Adhan) and Qur'an application that is highly customizable, free and open source.
|
||||
Muezzin supports many languages, advanced prayer options and many more.
|
||||
|
||||
Keywords: Athan, Adhan, Azan, Islam, Muslim, Prayers, times, Muezzin, Salah, Salat, Namaz, Islamic, Hijri, Quran, Qur'an, Koran.
|
||||
</p>
|
||||
</description>
|
||||
<content_rating type="oars-1.0" />
|
||||
<launchable type="desktop-id">io.github.dbchoco.muezzin.desktop</launchable>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<caption>Main Screen - Light Mode</caption>
|
||||
<image>https://github.com/DBChoco/Muezzin/blob/master/screenshots/lightMode.png?raw=true</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<caption>Main Screen - Dark Mode</caption>
|
||||
<image>https://github.com/DBChoco/Muezzin/blob/master/screenshots/darkMode.png?raw=true</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<caption>Settings Screen</caption>
|
||||
<image>https://github.com/DBChoco/Muezzin/blob/master/screenshots/settingsDark.png?raw=true</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<releases>
|
||||
<release version="v0.2.0" date="2022-04-04">
|
||||
<description>
|
||||
<p>General</p>
|
||||
<ul>
|
||||
<li>Added Qur'an reader with translations and transliterations.</li>
|
||||
<li>You can now double-click on the system tray (Windows and macOS).</li>
|
||||
<li>There is now a default background image for dark mode.</li>
|
||||
<li>Added Turkish (thanks to @emrergin).</li>
|
||||
<li>Menu bar is now hidden by default (press ALT to reveal it).</li>
|
||||
</ul>
|
||||
<p>BugFixes</p>
|
||||
<ul>
|
||||
<li>Fixed a few visual elements.</li>
|
||||
<li>Fixed a few things in the main.js and renderer.js.</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
</releases>
|
||||
</component>
|
||||
BIN
flatpak/io.github.dbchoco.muezzin.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
71
flatpak/io.github.dbchoco.muezzin.yml
Normal file
@@ -0,0 +1,71 @@
|
||||
app-id: io.github.dbchoco.muezzin
|
||||
runtime: org.freedesktop.Platform
|
||||
runtime-version: '21.08'
|
||||
sdk: org.freedesktop.Sdk
|
||||
base: org.electronjs.Electron2.BaseApp
|
||||
base-version: '21.08'
|
||||
sdk-extensions:
|
||||
- org.freedesktop.Sdk.Extension.node14
|
||||
command: muezzin-run
|
||||
separate-locales: false
|
||||
finish-args:
|
||||
- --share=ipc
|
||||
- --socket=x11
|
||||
- --socket=pulseaudio
|
||||
- --share=network
|
||||
build-options:
|
||||
append-path: /usr/lib/sdk/node14/bin
|
||||
env:
|
||||
NPM_CONFIG_LOGLEVEL: info
|
||||
modules:
|
||||
- name: muezzin
|
||||
buildsystem: simple
|
||||
build-options:
|
||||
env:
|
||||
XDG_CACHE_HOME: /run/build/muezzin/flatpak-node/cache
|
||||
npm_config_cache: /run/build/muezzin/flatpak-node/npm-cache
|
||||
npm_config_nodedir: /usr/lib/sdk/node14
|
||||
npm_config_offline: 'true'
|
||||
subdir: main
|
||||
sources:
|
||||
- type: archive
|
||||
url: https://github.com/DBChoco/Muezzin/archive/refs/tags/v0.2.0.tar.gz
|
||||
sha256: 2439555bec3f3553a9757a59598cf0422ba26d4e009f931a253240e0bef57c9e
|
||||
dest: main
|
||||
|
||||
- generated-sources.json
|
||||
|
||||
# Wrapper to launch the app
|
||||
- type: script
|
||||
dest-filename: muezzin-run
|
||||
commands:
|
||||
- zypak-wrapper.sh /app/main/muezzin "$@"
|
||||
|
||||
build-commands:
|
||||
# Install npm dependencies
|
||||
- npm install --offline
|
||||
# Build the app; in this example the `dist` script
|
||||
# in package.json runs electron-builder
|
||||
- |
|
||||
. ../flatpak-node/electron-builder-arch-args.sh
|
||||
jq '.build.linux.target="dir"' <<<$(<package.json) > package.json
|
||||
npm run dist -- $ELECTRON_BUILDER_ARCH_ARGS --linux --dir
|
||||
# Bundle app and dependencies
|
||||
- cp -a dist/linux*unpacked /app/main
|
||||
# Install app wrapper
|
||||
- install -Dm755 -t /app/bin/ ../muezzin-run
|
||||
|
||||
- name: platform-bootstrap
|
||||
buildsystem: simple
|
||||
build-commands:
|
||||
- |
|
||||
install -Dm644 io.github.dbchoco.muezzin.png /app/share/icons/hicolor/128x128/apps/$FLATPAK_ID.png
|
||||
install -Dm644 io.github.dbchoco.muezzin.desktop /app/share/applications/${FLATPAK_ID}.desktop
|
||||
install -Dm644 io.github.dbchoco.muezzin.metainfo.xml /app/share/metainfo/$FLATPAK_ID.appdata.xml
|
||||
sources:
|
||||
- type: file
|
||||
path: io.github.dbchoco.muezzin.metainfo.xml
|
||||
- type: file
|
||||
path: io.github.dbchoco.muezzin.png
|
||||
- type: file
|
||||
path: io.github.dbchoco.muezzin.desktop
|
||||
14231
package-lock.json
generated
Normal file
110
package.json
Normal file
@@ -0,0 +1,110 @@
|
||||
{
|
||||
"name": "muezzin",
|
||||
"version": "0.2.0",
|
||||
"description": "Prayer Time Caller",
|
||||
"main": "src/main/main.js",
|
||||
"scripts": {
|
||||
"start": "electron-forge start",
|
||||
"package": "electron-forge package",
|
||||
"make": "electron-forge make",
|
||||
"dist": "electron-builder",
|
||||
"build": "electron-builder build --linux --win --publish never",
|
||||
"deploy": "electron-builder build --linux --win --publish always"
|
||||
},
|
||||
"icon": "ressources/images/icon.png",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/DBChoco/Muezzin.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "DBChoco <smuky2k@gmail.com>",
|
||||
"license": "CC0-1.0",
|
||||
"devDependencies": {
|
||||
"@electron-forge/cli": "^6.0.0-beta.63",
|
||||
"@electron-forge/maker-deb": "^6.0.0-beta.63",
|
||||
"@electron-forge/maker-rpm": "^6.0.0-beta.63",
|
||||
"@electron-forge/maker-squirrel": "^6.0.0-beta.63",
|
||||
"@electron-forge/maker-zip": "^6.0.0-beta.63",
|
||||
"electron": "^17.0.0",
|
||||
"electron-builder": "^22.14.13"
|
||||
},
|
||||
"dependencies": {
|
||||
"adhan": "^4.3.1",
|
||||
"auto-launch": "^5.0.5",
|
||||
"bootstrap": "^5.1.3",
|
||||
"bootstrap-dark-5": "^1.1.3",
|
||||
"electron-store": "^8.0.1",
|
||||
"ip-geolocation-api-javascript-sdk": "^1.0.7",
|
||||
"weather.js": "^0.1.0"
|
||||
},
|
||||
"build": {
|
||||
"appId": "com.muezzin.app",
|
||||
"publish": [
|
||||
{
|
||||
"provider": "github",
|
||||
"owner": "DBChoco",
|
||||
"repo": "Muezzin"
|
||||
}
|
||||
],
|
||||
"win": {
|
||||
"icon": "ressources/images/icon.ico",
|
||||
"target": "nsis"
|
||||
},
|
||||
"linux": {
|
||||
"icon": "ressources/images/icon.png",
|
||||
"category": "Utility",
|
||||
"target": [
|
||||
"AppImage",
|
||||
"snap",
|
||||
"tar.gz",
|
||||
"pacman",
|
||||
"deb"
|
||||
]
|
||||
},
|
||||
"mac": {
|
||||
"icon": "ressources/images/icon.png",
|
||||
"category": "public.app-category.utilities",
|
||||
"target": [
|
||||
"dmg"
|
||||
]
|
||||
},
|
||||
"appx": {
|
||||
"applicationId": "Muezzin",
|
||||
"backgroundColor": "#382bcc",
|
||||
"publisher": "DBChoco",
|
||||
"languages": [
|
||||
"EN",
|
||||
"FR",
|
||||
"ES",
|
||||
"AR",
|
||||
"DE",
|
||||
"IT",
|
||||
"NB",
|
||||
"SV",
|
||||
"DA",
|
||||
"NL",
|
||||
"UR"
|
||||
]
|
||||
},
|
||||
|
||||
"snap": {
|
||||
"confinement": "strict",
|
||||
"summary": "Islamic prayer times application",
|
||||
"grade": "stable"
|
||||
},
|
||||
"linux": {
|
||||
"icon": "ressources/images/logo.png",
|
||||
"category": "Utility",
|
||||
"target": ["AppImage", "snap", "tar.gz", "pacman"]
|
||||
},
|
||||
"mac": {
|
||||
"icon": "ressources/images/logo.png",
|
||||
"category": "public.app-category.utilities",
|
||||
"target": ["dmg"]
|
||||
}
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/DBChoco/Muezzin/issues"
|
||||
},
|
||||
"homepage": "https://github.com/DBChoco/Muezzin#readme"
|
||||
}
|
||||
BIN
ressources/audio/Adhan - Mecca.mp3
Normal file
BIN
ressources/audio/Adhan - al-Aqsa.mp3
Normal file
BIN
ressources/audio/Bismillah - Fatih Sefaragic.mp3
Normal file
BIN
ressources/audio/dua.mp3
Normal file
6
ressources/fonts/FontAwesome/all.min.css
vendored
Normal file
BIN
ressources/fonts/arabic/Basmalah Ver01.otf
Normal file
BIN
ressources/fonts/arabic/Symbols1_Ver02.otf
Normal file
14
ressources/fonts/arabic/fonts.css
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
Source: https://fonts.qurancomplex.gov.sa/ & https://cdn.jsdelivr.net/gh/fawazahmed0/quran-api@1/fonts.json
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: arabic-symbols;
|
||||
src: url(Basmalah\ Ver01.otf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: arabic;
|
||||
src: url(hafs-uthmanic-v14-full-org.ttf);
|
||||
}
|
||||
|
||||
BIN
ressources/fonts/arabic/hafs-uthmanic-v14-full-org.ttf
Normal file
1838
ressources/fonts/weather-icons/css/weather-icons.css
Normal file
BIN
ressources/fonts/weather-icons/font/weathericons-regular-webfont.ttf
Executable file
BIN
ressources/fonts/weather-icons/font/weathericons-regular-webfont.woff2
Executable file
BIN
ressources/fonts/webfonts/fa-brands-400.ttf
Normal file
BIN
ressources/fonts/webfonts/fa-brands-400.woff2
Normal file
BIN
ressources/fonts/webfonts/fa-regular-400.ttf
Normal file
BIN
ressources/fonts/webfonts/fa-regular-400.woff2
Normal file
BIN
ressources/fonts/webfonts/fa-solid-900.ttf
Normal file
BIN
ressources/fonts/webfonts/fa-solid-900.woff2
Normal file
BIN
ressources/fonts/webfonts/fa-v4compatibility.ttf
Normal file
BIN
ressources/fonts/webfonts/fa-v4compatibility.woff2
Normal file
BIN
ressources/images/bgImage.jpg
Normal file
|
After Width: | Height: | Size: 808 KiB |
BIN
ressources/images/bgImage_dark.avif
Normal file
|
After Width: | Height: | Size: 296 KiB |
BIN
ressources/images/icon.ico
Normal file
|
After Width: | Height: | Size: 133 KiB |
BIN
ressources/images/icon.png
Normal file
|
After Width: | Height: | Size: 138 KiB |
1
ressources/quran/chapters.json
Normal file
1
ressources/quran/languages.json
Normal file
1
ressources/quran/translations.json
Normal file
1436
ressources/timezones.json
Normal file
BIN
screenshots/darkMode.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
screenshots/lightMode.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
screenshots/quranDark.png
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
screenshots/settingsDark.png
Normal file
|
After Width: | Height: | Size: 79 KiB |
14
snapcraft.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
name: muezzin # you probably want to 'snapcraft register <name>'
|
||||
base: core20 # the base snap is the execution environment for this snap
|
||||
version: '0.1.1' # just for humans, typically '1.2+git' or '1.3.2'
|
||||
summary: Highly customizable prayer times application # 79 char long summary
|
||||
description: |
|
||||
Highly customizable **prayer times** application with custom background and call to prayers (Adhan / Azan). **Multi language** support with many more coming in the future insha'Allah.
|
||||
|
||||
grade: stable # must be 'stable' to release into candidate/stable channels
|
||||
confinement: strict # use 'strict' once you have the right plugs and slots
|
||||
|
||||
parts:
|
||||
my-part:
|
||||
# See 'snapcraft plugins'
|
||||
plugin: nil
|
||||
113
src/common/allStrings
Normal file
@@ -0,0 +1,113 @@
|
||||
|
||||
Language
|
||||
Time format
|
||||
24 Hour
|
||||
12 Hour
|
||||
Show seconds
|
||||
Date format
|
||||
DD/MM/YYYY
|
||||
MM/DD/YYYY
|
||||
YYYY/MM/DD
|
||||
Notifications
|
||||
Enable notifications
|
||||
Coordinates
|
||||
Latitude
|
||||
Longitude
|
||||
Time zone
|
||||
Enable Adhan
|
||||
Adhan Mecca
|
||||
Adhan al-Aqsa
|
||||
Custom Adhan
|
||||
Du'a after Adhan
|
||||
Theme
|
||||
Dark Mode
|
||||
Background Image
|
||||
Enable Background Image
|
||||
Calculation Methods
|
||||
Muslim World League
|
||||
Egyptian
|
||||
Karachi
|
||||
Umm al-Qura
|
||||
Dubai
|
||||
Qatar
|
||||
Kuwait
|
||||
Moonsighting Committee
|
||||
Singapore
|
||||
Turkey
|
||||
Tehran
|
||||
ISNA (America)
|
||||
Madhab
|
||||
Shafi
|
||||
Hanafi
|
||||
High Latitude Rule
|
||||
Middle of the Night
|
||||
Seventh of the Night
|
||||
Twilight Angle
|
||||
Polar Circle Resolution
|
||||
Closest City
|
||||
Closest Date
|
||||
Do not calculate
|
||||
Shafaq
|
||||
General
|
||||
Red Twilight (ahmer)
|
||||
White Twilight (abyad)
|
||||
Return
|
||||
General
|
||||
Location
|
||||
Audio
|
||||
Appearance
|
||||
Advanced
|
||||
Muezzin
|
||||
Auto Start
|
||||
Start at launch
|
||||
Copyright 2022, Muezzin, All rights reserved.
|
||||
Indeed, prayer has been decreed upon the believers a decree of specified times
|
||||
Qur'an: 4/103
|
||||
Fajr
|
||||
Sunrise
|
||||
Dhuhr
|
||||
Asr
|
||||
Maghrib
|
||||
Isha
|
||||
Now
|
||||
Start Up Sound
|
||||
Play sound on startup
|
||||
System tray
|
||||
Minimize to tray
|
||||
Custom settings
|
||||
Enable Custom Calculation Settings
|
||||
Fajr Angle
|
||||
Maghrib Angle
|
||||
Isha Angle
|
||||
Delay after Maghrib
|
||||
Delay (minutes)
|
||||
France
|
||||
Russia
|
||||
Gulf Region
|
||||
Preferences
|
||||
Reset settings
|
||||
Adjustments
|
||||
Enable adjustments
|
||||
Fajr Adjustments
|
||||
Dhurh Adjustments
|
||||
Asr Adjustments
|
||||
Maghrib Adjustments
|
||||
Isha Adjustments
|
||||
Show Sunnah times
|
||||
Middle of the night
|
||||
Third of the night
|
||||
Start minimized
|
||||
Update available
|
||||
Version
|
||||
is available for download on GitHub
|
||||
Download
|
||||
Later
|
||||
|
||||
Qur'an
|
||||
Font
|
||||
Font size
|
||||
Translation
|
||||
Show translation
|
||||
Different language from application
|
||||
Transliteration
|
||||
Show transliteration
|
||||
90
src/common/common.js
Normal file
@@ -0,0 +1,90 @@
|
||||
module.exports = {
|
||||
foo: function () {
|
||||
// whatever
|
||||
},
|
||||
toggleDarkMode: function toggleDarkMode(darkMode, mainCSS){
|
||||
var head = document.getElementsByTagName('HEAD')[0];
|
||||
|
||||
var link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.type = 'text/css';
|
||||
|
||||
var css = document.createElement('link');
|
||||
css.type = 'text/css';
|
||||
css.href = mainCSS
|
||||
|
||||
var shaders = document.getElementsByClassName("shader")
|
||||
if (darkMode){
|
||||
link.href = '../../node_modules/bootstrap-dark-5/dist/css/bootstrap-dark.min.css';
|
||||
changeButtons(darkMode)
|
||||
changeNavLink(darkMode)
|
||||
document.body.style.borderColor = "#FFFFFF";
|
||||
//document.body.style.backgroundColor = "#212121";
|
||||
for (let element of shaders){
|
||||
element.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
}
|
||||
else{
|
||||
link.href = '../../node_modules/bootstrap-dark-5/dist/css/bootstrap.min.css';
|
||||
changeButtons(darkMode)
|
||||
changeNavLink(darkMode)
|
||||
document.body.style.borderColor = "#000000";
|
||||
//document.body.style.backgroundColor = "#FFFFFF";
|
||||
for (let element of shaders){
|
||||
element.style.backgroundColor = 'rgba(255, 255, 255, 0.5)'
|
||||
}
|
||||
}
|
||||
|
||||
css.rel = 'stylesheet';
|
||||
|
||||
head.appendChild(link);
|
||||
head.appendChild(css);
|
||||
|
||||
function changeButtons(darkMode){
|
||||
if (darkMode){
|
||||
var buttons = document.getElementsByClassName("btn")
|
||||
for (let element of buttons){
|
||||
element.classList.add("btn-light")
|
||||
if (element.classList.contains("btn-dark")){
|
||||
element.classList.remove("btn-dark")
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
var buttons = document.getElementsByClassName("btn")
|
||||
for (let element of buttons){
|
||||
element.classList.add("btn-dark")
|
||||
if (element.classList.contains("btn-light")){
|
||||
element.classList.remove("btn-light")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function changeNavLink(darkMode){
|
||||
var buttons = document.getElementsByClassName("nav-pills")
|
||||
var buttons2 = document.getElementsByClassName("nav-link")
|
||||
|
||||
if (darkMode){
|
||||
for (let element of buttons){
|
||||
element.classList.add("dark-pills")
|
||||
element.classList.remove("light-pills")
|
||||
}
|
||||
for (let element of buttons2){
|
||||
element.classList.add("dark-link")
|
||||
element.classList.remove("light-link")
|
||||
}
|
||||
}
|
||||
else{
|
||||
for (element of buttons){
|
||||
element.classList.add("light-pills")
|
||||
element.classList.remove("dark-pills")
|
||||
}
|
||||
for (element of buttons2){
|
||||
element.classList.add("light-link")
|
||||
element.classList.remove("dark-link")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
1402
src/common/language.js
Normal file
124
src/main/index.html
Normal file
@@ -0,0 +1,124 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self'; style-src 'self' 'unsafe-inline'">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="../../node_modules/bootstrap-dark-5/dist/css/bootstrap-night.min.css" rel="stylesheet" >
|
||||
<link href="../../ressources/fonts/FontAwesome/all.min.css" rel="stylesheet" >
|
||||
<link href="../../ressources/fonts/weather-icons/css/weather-icons.css" rel="stylesheet" >
|
||||
<script src="../../node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||
<link href="styles.css" rel="stylesheet">
|
||||
<title>Muezzin</title>
|
||||
</head>
|
||||
|
||||
<div class="center" id="loader">
|
||||
<div>
|
||||
<div class="spinner-border" style="width: 3rem; height: 3rem;" role="status"></div>
|
||||
<strong>
|
||||
<h1>
|
||||
Muezzin
|
||||
</h1>
|
||||
</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="updateModal" tabindex="-1" aria-labelledby="updateModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="updateModalLabel">Update</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" id="modalClose"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="modalBody">
|
||||
X
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" id="modalButton1">Download</button>
|
||||
<button type="button" class="btn btn-secondary" id="modalButton2">Later</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<header>
|
||||
|
||||
<h1 id="title">Muezzin</h1>
|
||||
|
||||
<div id="weatherContainer">
|
||||
<div id="weatherTemp"> </div>
|
||||
</div>
|
||||
|
||||
</header>
|
||||
<body class="d-flex flex-column min-vh-100">
|
||||
|
||||
<div id="mainContainer">
|
||||
<div id="main" class="d-flex flex-column">
|
||||
<h1 class="shader" id="clock">00:00</h1>
|
||||
<h3 class="shader" id="dateLoc">Date today - Location</h3>
|
||||
<h1 class="shader" id="timeLeft">Time until XYZ prayer: 00:00</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="boxContainer">
|
||||
<div class="box" id="box">
|
||||
<div class="grid-container shader" id="prayerGrid">
|
||||
<div class="grid-item left grid-top" id="fajr"> Fajr </div>
|
||||
<div class="grid-item right grid-top" id="fajrTime"> 00:00 </div>
|
||||
<div class="grid-item left" id="sunrise"> Sunrise </div>
|
||||
<div class="grid-item right" id="sunriseTime"> 00:00 </div>
|
||||
<div class="grid-item left" id="dhuhr"> Duhr </div>
|
||||
<div class="grid-item right" id="dhuhrTime"> 00:00 </div>
|
||||
<div class="grid-item left" id="asr"> Asr </div>
|
||||
<div class="grid-item right" id="asrTime"> 00:00 </div>
|
||||
<div class="grid-item left" id="maghrib"> Maghrib </div>
|
||||
<div class="grid-item right" id="maghribTime"> 00:00 </div>
|
||||
<div class="grid-item left grid-bottom" id="isha"> Isha </div>
|
||||
<div class="grid-item right grid-bottom" id="ishaTime"> 00:00 </div>
|
||||
<div class="grid-item left motn" id="motn"> Middle of the night </div>
|
||||
<div class="grid-item right motn" id="motnTime"> 00:00 </div>
|
||||
<div class="grid-item left totn" id="totn"> Third of the night </div>
|
||||
<div class="grid-item right totn" id="totnTime"> 00:00 </div>
|
||||
</div>
|
||||
<div class="box-bottom">
|
||||
<input data-provide="datepicker" type="date" id="calendar" name="calendar">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- You can also require other files to run in this process -->
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
<footer class="mt-auto" >
|
||||
<div id="footer" >
|
||||
<div id="upperPart">
|
||||
<div id="audioControls">
|
||||
<button type="button" id="stopB" class="btn btn-dark"><i class="fa fa-stop"></i></button>
|
||||
<button type="button" id="playB" class="btn btn-dark"><i class="fa fa-play"></i></button>
|
||||
<div id="volume">
|
||||
<i class="fa fa-volume-down"></i>
|
||||
<input type="range" class="form-range" id="volSlider">
|
||||
<i class="fa fa-volume-up"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div id="buttons">
|
||||
<button href="../quran/quran.html" id="quranButton" class="btn btn-dark">
|
||||
<i class="fa-solid fa-book-quran"></i>
|
||||
Qur'an
|
||||
</button>
|
||||
<button href="../settings/settings.html" id="settingsWheel" class="btn btn-dark">
|
||||
Settings
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</html>
|
||||
811
src/main/main.js
Normal file
@@ -0,0 +1,811 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const {app, BrowserWindow, ipcMain, Tray, Menu, Notification, nativeImage, net, shell} = require('electron')
|
||||
const path = require('path')
|
||||
const Store = require('electron-store');
|
||||
const store = new Store();
|
||||
const adhan = require('adhan')
|
||||
const language = require('../common/language.js')
|
||||
const AutoLaunch = require('auto-launch');
|
||||
var autoLauncher = new AutoLaunch({
|
||||
name: "Muezzin",
|
||||
mac:{
|
||||
useLaunchAgent: true
|
||||
}
|
||||
});
|
||||
|
||||
let tray = null
|
||||
let mainWindow, mediaWindow;
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
minWidth: 600,
|
||||
minHeight: 600,
|
||||
backgroundColor:"#212121",
|
||||
icon: '../../ressources/images/icon.png',
|
||||
webPreferences: {
|
||||
nodeIntegration: false, // is default value after Electron v5
|
||||
contextIsolation: true, // protect against prototype pollution
|
||||
enableRemoteModule: false, // turn off remote
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
webviewTag: true
|
||||
}
|
||||
})
|
||||
|
||||
//DEBUG
|
||||
//mainWindow.webContents.openDevTools()
|
||||
|
||||
const isMac = process.platform === 'darwin'
|
||||
const template = [
|
||||
// { role: 'appMenu' }
|
||||
...(isMac ? [{
|
||||
label: app.name,
|
||||
submenu: [
|
||||
{ role: 'about' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'services' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'hide' },
|
||||
{ role: 'hideOthers' },
|
||||
{ role: 'unhide' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'quit' }
|
||||
]
|
||||
}] : []),
|
||||
// { role: 'fileMenu' }
|
||||
{
|
||||
label: 'File',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Reset settings',
|
||||
click: function(){
|
||||
store.clear();
|
||||
app.relaunch()
|
||||
app.exit()
|
||||
}
|
||||
},
|
||||
isMac ? { role: 'close' } : { role: 'quit' }
|
||||
]
|
||||
},
|
||||
// { role: 'viewMenu' }
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{ role: 'resetZoom' },
|
||||
{ role: 'zoomIn' },
|
||||
{ role: 'zoomOut' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'togglefullscreen' }
|
||||
]
|
||||
},
|
||||
// { role: 'windowMenu' }
|
||||
{
|
||||
label: 'Window',
|
||||
submenu: [
|
||||
{ role: 'minimize' },
|
||||
{ role: 'zoom' },
|
||||
...(isMac ? [
|
||||
{ type: 'separator' },
|
||||
{ role: 'front' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'window' }
|
||||
] : [
|
||||
{ role: 'close' }
|
||||
])
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Debug',
|
||||
submenu: [
|
||||
{ role: 'reload' },
|
||||
{ role: 'forceReload' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'toggleDevTools' }
|
||||
]
|
||||
},
|
||||
{
|
||||
role: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Website',
|
||||
click: async () => {
|
||||
await shell.openExternal('https://github.com/DBChoco/Muezzin')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Reddit',
|
||||
click: async () => {
|
||||
await shell.openExternal('https://www.reddit.com/r/Muezzin/')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Discord',
|
||||
click: async () => {
|
||||
await shell.openExternal('https://discord.gg/cpF9TTstN5')
|
||||
}
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Report an issue',
|
||||
click: async () => {
|
||||
await shell.openExternal('https://github.com/DBChoco/Muezzin/issues/new')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const menu = Menu.buildFromTemplate(template)
|
||||
Menu.setApplicationMenu(menu)
|
||||
mainWindow.setMenuBarVisibility(false)
|
||||
mainWindow.setAutoHideMenuBar(true)
|
||||
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('src/main/index.html')
|
||||
|
||||
mainWindow.maximize();
|
||||
|
||||
mainWindow.on('minimize',function(event){
|
||||
event.preventDefault();
|
||||
mainWindow.hide();
|
||||
});
|
||||
|
||||
mainWindow.on('close', function (event) {
|
||||
if(!app.isQuiting && settings.systray){
|
||||
event.preventDefault();
|
||||
mainWindow.hide();
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
app.isQuiting = true;
|
||||
app.quit();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
//Create hidden mediaPlayer
|
||||
mediaWindow = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: false, // is default value after Electron v5
|
||||
contextIsolation: true, // protect against prototype pollution
|
||||
enableRemoteModule: false, // turn off remote
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
}
|
||||
});
|
||||
|
||||
mediaWindow.loadFile('src/mediaPlayer/mediaPlayer.html');
|
||||
}
|
||||
|
||||
|
||||
app.on('before-quit', function () {
|
||||
app.isQuiting = true;
|
||||
});
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
app.on('activate', function () {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
|
||||
let iconPath;
|
||||
if (process.platform == "win32"){
|
||||
iconPath = path.join(__dirname, '../../ressources/images/icon.ico');
|
||||
} else{
|
||||
iconPath = path.join(__dirname, '../../ressources/images/icon.png');
|
||||
}
|
||||
if (process.platform == "darwin"){
|
||||
tray = new Tray(nativeImage.createFromPath(iconPath).resize({ width: 16, height: 16 }))
|
||||
}
|
||||
else{
|
||||
tray = new Tray(nativeImage.createFromPath(iconPath))
|
||||
}
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{ label: 'Open', click: function(){
|
||||
mainWindow.show(); }},
|
||||
{ label: 'Quit', click: function(){
|
||||
app.isQuiting = true;
|
||||
app.quit();}}
|
||||
])
|
||||
tray.setToolTip('Muezzin')
|
||||
tray.setContextMenu(contextMenu)
|
||||
tray.addListener("double-click", function(){
|
||||
mainWindow.show();
|
||||
})
|
||||
|
||||
checkFirstTime()
|
||||
loadSettings();
|
||||
setUpHandlers();
|
||||
checkTime();
|
||||
setUpdates()
|
||||
})
|
||||
|
||||
|
||||
|
||||
var lat, lon, calculationMethod, prayerTimes, adhanPath;
|
||||
var customValues, delay;
|
||||
var prayerTimes, datePrayerTimes, tomorrowPrayers;
|
||||
var settings
|
||||
var langFajr, langDhuhr, langAsr, langMaghrib, langIsha, langNow;
|
||||
|
||||
var adjustements;
|
||||
var updateInterval;
|
||||
var startup = true; // To check if the app just started or not when going back to the main page.
|
||||
var today = new Date
|
||||
|
||||
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
// for applications and their menu bar to stay active until the user quits
|
||||
// explicitly with Cmd + Q.
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin' && settings.systray) app.quit()
|
||||
})
|
||||
|
||||
function setUpdates(){
|
||||
setTimeout(function(){
|
||||
getVersion()
|
||||
}, 3000);
|
||||
updateInterval = setInterval(function(){
|
||||
getVersion()
|
||||
}, 600000) //10 minutes
|
||||
}
|
||||
|
||||
function getVersion(){
|
||||
console.log("Looking for updates")
|
||||
const request = net.request({
|
||||
method: 'GET',
|
||||
protocol: 'http:',
|
||||
hostname: 'api.github.com',
|
||||
path: '/repositories/459335904/releases/latest',
|
||||
redirect: 'follow'
|
||||
});
|
||||
request.on('response', (response) => {
|
||||
//console.log(`STATUS: ${response.statusCode}`);
|
||||
//console.log(`HEADERS: ${JSON.stringify(response.headers)}`);
|
||||
response.on('data', (chunk) => {
|
||||
if (app.getVersion() < JSON.parse(chunk).name){
|
||||
mainWindow.webContents.send('update-available', [app.getVersion(), JSON.parse(chunk).name]);
|
||||
clearInterval(updateInterval);
|
||||
}
|
||||
});
|
||||
});
|
||||
request.on('finish', () => {
|
||||
//console.log('Request is Finished')
|
||||
});
|
||||
request.on('abort', () => {
|
||||
console.log('Request is Aborted')
|
||||
});
|
||||
request.on('error', (error) => {
|
||||
console.log(`ERROR: ${JSON.stringify(error)}`)
|
||||
});
|
||||
request.on('close', (error) => {
|
||||
//console.log('Last Transaction has occured')
|
||||
});
|
||||
request.setHeader('Content-Type', 'application/json');
|
||||
request.end();
|
||||
}
|
||||
|
||||
function showNotification (message) {
|
||||
if (Notification.isSupported()){
|
||||
const NOTIFICATION_TITLE = 'Muezzin'
|
||||
const NOTIFICATION_BODY = message
|
||||
new Notification({ title: NOTIFICATION_TITLE, body: NOTIFICATION_BODY, icon:"../ressources/images/icon.png" }).show()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for Athan time and current time, then if they are the same, it plays the Athan
|
||||
*/
|
||||
function checkTime(){
|
||||
var interval = setInterval(function(){
|
||||
var prayers = nextPrayer();
|
||||
if (prayers != undefined && prayers[0] != undefined && (settings.adhanCheck || settings.notifCheck)){
|
||||
var timeUntilCurrentPrayer = timeUntilPrayer(prayers[0])
|
||||
//console.log(timeUntilCurrentPrayer)
|
||||
if(timeUntilCurrentPrayer[0] == -1 && timeUntilCurrentPrayer[1] == -1 && timeUntilCurrentPrayer[2] == 0){ //-1 because math.floor
|
||||
//if(timeUntilCurrentPrayer[0] == -1 && timeUntilCurrentPrayer[1] == -26 && timeUntilCurrentPrayer[2] == 0){ //TESTING
|
||||
if (settings.adhanCheck){
|
||||
mediaWindow.webContents.send('play', adhanPath);
|
||||
}
|
||||
if (settings.notifCheck){
|
||||
showNotification(langNow + ": " + prayers[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 1000)
|
||||
setInterval(function(){
|
||||
if (today.getDate != (new Date).getDate){
|
||||
mainWindow.webContents.send('update');
|
||||
}
|
||||
}, 900000)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads all required variables from the store
|
||||
*/
|
||||
async function loadSettings(){
|
||||
lat = await store.get('latitude', 0.00);
|
||||
lon = await store.get('longitude', 0.00);
|
||||
timezone = await store.get('timezone', 'Europe/Brussels');
|
||||
|
||||
calculationMethod = await store.get("calculationMethod", {
|
||||
calcMethod: 'MWL',
|
||||
madhab: 'Shafi',
|
||||
hlr: 'TA',
|
||||
pcr: 'CC',
|
||||
shafaq: 'shafaqG'
|
||||
})
|
||||
|
||||
settings = await store.get("settings", {
|
||||
startupSound: false,
|
||||
notifCheck: true,
|
||||
systray: true,
|
||||
adhanCheck: true,
|
||||
autoStart: true,
|
||||
minStart: false
|
||||
})
|
||||
|
||||
|
||||
adhanPath = await store.get('adhanFile', [false, "../../ressources/audio/Adhan - Mecca.mp3", true]);
|
||||
lang = await store.get('language', 'en');
|
||||
loadLang();
|
||||
customValues = await store.get('customSettings', [false, 0,0,0]);
|
||||
delay = await store.get('delay', [false, 0]);
|
||||
|
||||
adjustements = await store.get('adj', [false, 0,0,0,0,0]);
|
||||
|
||||
if (settings.minStart && startup){
|
||||
mainWindow.hide()
|
||||
}
|
||||
setAutoStart(settings.autoStart)
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Takes all the loaded settings and calculated the prayers times for 'date'
|
||||
* @param {Date} date
|
||||
* @return {adhan.PrayerTimes} prayerTimes
|
||||
*/
|
||||
function calcPrayerTimes(date = new Date()){
|
||||
console.log("Calculating prayer times")
|
||||
var coordinates = new adhan.Coordinates(lat, lon)
|
||||
|
||||
// https://github.com/batoulapps/adhan-js/blob/master/METHODS.md
|
||||
|
||||
//TO add one, change CalculationMethod.js, Adhan.d.ts and Adhan.js
|
||||
if (customValues != undefined && !customValues[0]){
|
||||
switch(calculationMethod.calcMethod) {
|
||||
case "MWL":
|
||||
params = adhan.CalculationMethod.MuslimWorldLeague();
|
||||
break;
|
||||
case "Egyptian":
|
||||
params = adhan.CalculationMethod.Egyptian();
|
||||
break;
|
||||
case "Karachi":
|
||||
params = adhan.CalculationMethod.Karachi();
|
||||
break;
|
||||
case "UAQ":
|
||||
params = adhan.CalculationMethod.UmmAlQura();
|
||||
break;
|
||||
case "Dubai":
|
||||
params = adhan.CalculationMethod.Dubai();
|
||||
break;
|
||||
case "Qatar":
|
||||
params = adhan.CalculationMethod.Qatar();
|
||||
break;
|
||||
case "Kuwait":
|
||||
params = adhan.CalculationMethod.Kuwait();
|
||||
break;
|
||||
case "MC":
|
||||
params = adhan.CalculationMethod.MoonsightingCommittee();
|
||||
break;
|
||||
case "Singapore":
|
||||
params = adhan.CalculationMethod.Singapore();
|
||||
break;
|
||||
case "Turkey":
|
||||
params = adhan.CalculationMethod.Turkey();
|
||||
break;
|
||||
case "Tehran":
|
||||
params = adhan.CalculationMethod.Tehran();
|
||||
break;
|
||||
case "ISNA":
|
||||
params = adhan.CalculationMethod.NorthAmerica();
|
||||
break;
|
||||
case "France12":
|
||||
params = adhan.CalculationMethod.France12();
|
||||
break;
|
||||
case "France15":
|
||||
params = adhan.CalculationMethod.France15();
|
||||
break;
|
||||
case "France18":
|
||||
params = adhan.CalculationMethod.France18();
|
||||
break;
|
||||
case "Russia":
|
||||
params = adhan.CalculationMethod.Russia();
|
||||
break;
|
||||
case "Gulf":
|
||||
params = adhan.CalculationMethod.Gulf();
|
||||
break;
|
||||
default:
|
||||
params = adhan.CalculationMethod.MuslimWorldLeague();
|
||||
}
|
||||
}
|
||||
else{
|
||||
params = adhan.CalculationMethod.Other();
|
||||
params.fajrAngle = customValues[1]
|
||||
params.maghribAngle = customValues[2]
|
||||
params.ishaAngle = customValues[3]
|
||||
}
|
||||
|
||||
if (delay[0]){
|
||||
params.ishaInterval = delay[1]
|
||||
}
|
||||
|
||||
switch(calculationMethod.madhab){
|
||||
case "Shafi":
|
||||
params.madhab = adhan.Madhab.Shafi;
|
||||
break;
|
||||
case "Hanafi":
|
||||
params.madhab = adhan.Madhab.Hanafi;
|
||||
break;
|
||||
default:
|
||||
params.madhab = adhan.Madhab.Shafi;
|
||||
}
|
||||
|
||||
switch(calculationMethod.hlr){
|
||||
case "MOTN":
|
||||
params.HighLatitudeRule = adhan.HighLatitudeRule.MiddleOfTheNight;
|
||||
break;
|
||||
case "SOTN":
|
||||
params.HighLatitudeRule = adhan.HighLatitudeRule.SeventhOfTheNight;
|
||||
break;
|
||||
case "TA":
|
||||
params.HighLatitudeRule = adhan.HighLatitudeRule.TwilightAngle;
|
||||
break;
|
||||
default:
|
||||
params.HighLatitudeRule = adhan.HighLatitudeRule.recommended(coordinates)
|
||||
}
|
||||
|
||||
switch(calculationMethod.pcr){
|
||||
case "CC":
|
||||
params.PolarCircleResolution = adhan.PolarCircleResolution.AqrabBalad;
|
||||
break;
|
||||
case "CD":
|
||||
params.PolarCircleResolution = adhan.PolarCircleResolution.AqrabYaum;
|
||||
break;
|
||||
case "UND":
|
||||
params.PolarCircleResolution = adhan.PolarCircleResolution.Unresolved;
|
||||
break;
|
||||
default:
|
||||
params.PolarCircleResolution = adhan.PolarCircleResolution.AqrabBalad;
|
||||
}
|
||||
|
||||
switch(calculationMethod.shafaq){
|
||||
case "shafaqG":
|
||||
params.shafaq = adhan.Shafaq.General;
|
||||
break;
|
||||
case "shafaqR":
|
||||
params.shafaq = adhan.Shafaq.Ahmer;
|
||||
break;
|
||||
case "shafaqW":
|
||||
params.shafaq = adhan.Shafaq.Abyad;
|
||||
break;
|
||||
default:
|
||||
params.shafaq = adhan.Shafaq.General;
|
||||
}
|
||||
|
||||
if(adjustements[0]){
|
||||
params.adjustments.fajr = adjustements[1]
|
||||
params.adjustments.dhuhr = adjustements[2]
|
||||
params.adjustments.asr = adjustements[3]
|
||||
params.adjustments.maghrib = adjustements[4]
|
||||
params.adjustments.isha = adjustements[5]
|
||||
}
|
||||
|
||||
let calculatedTimes = new adhan.PrayerTimes(coordinates, date, params);
|
||||
|
||||
return calculatedTimes;
|
||||
}
|
||||
|
||||
|
||||
//Sets up all the IPC handlers for communication with renderers
|
||||
async function setUpHandlers(){
|
||||
ipcMain.handle('getStoreValue', (event, key, defaultValue) => {
|
||||
if (defaultValue != undefined){
|
||||
return store.get(key, defaultValue);
|
||||
}
|
||||
else{
|
||||
return store.get(key);
|
||||
}
|
||||
});
|
||||
ipcMain.handle('setStoreValue', (event, key, value) => {
|
||||
return store.set(key, value);
|
||||
});
|
||||
|
||||
ipcMain.handle('prayers', (event, message) => {
|
||||
console.log("Requesting prayer times for today")
|
||||
waitFor(lat, prayerTimes = calcPrayerTimes())
|
||||
event.sender.send('prayersReply', prayerTimes)
|
||||
});
|
||||
ipcMain.handle('date-request', (event, message) => {
|
||||
console.log("Requesting prayer times for " + message)
|
||||
waitFor(lat, datePrayerTimes = calcPrayerTimes(new Date(message)));
|
||||
event.sender.send('date-reply', datePrayerTimes)
|
||||
});
|
||||
ipcMain.handle('tomorrow-request', (event, message) => {
|
||||
console.log("Requesting prayer times for " + message.toDateString())
|
||||
waitFor(lat, tomorrowPrayers = calcPrayerTimes(message))
|
||||
event.sender.send('tomorrow-reply', tomorrowPrayers)
|
||||
});
|
||||
|
||||
//Media Handlers
|
||||
ipcMain.handle('play', (event, message) => {
|
||||
mediaWindow.webContents.send('play', adhanPath);
|
||||
});
|
||||
ipcMain.handle('stop', (event, message) => {
|
||||
mediaWindow.webContents.send('stop', {});
|
||||
});
|
||||
ipcMain.handle('volume-request', (event, message) => {
|
||||
mediaWindow.webContents.send('volume-reply', message);
|
||||
});
|
||||
ipcMain.handle('progress-request', (event, message) => {
|
||||
mainWindow.webContents.send('progress-reply', message);
|
||||
});
|
||||
|
||||
ipcMain.handle("settingsO", function(){
|
||||
})
|
||||
ipcMain.handle("settingsC", function(){
|
||||
startup = false;
|
||||
loadSettings()
|
||||
//calcPrayerTimes()
|
||||
})
|
||||
|
||||
ipcMain.handle("startup-request", function(){
|
||||
mediaWindow.webContents.send('startup-reply', settings.startupSound);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function calcTomorrowPrayers(){
|
||||
const today = new Date();
|
||||
const tomorrow = new Date();
|
||||
tomorrow.setDate(today.getDate() + 1);
|
||||
tomorrowPrayers = calcPrayerTimes(tomorrow)
|
||||
}
|
||||
|
||||
|
||||
//Waits for someting to be defined before doing some other thing
|
||||
async function waitFor(something, doSomething){
|
||||
var valueChecker = setInterval(function(){
|
||||
if (something != undefined){
|
||||
clearInterval(valueChecker)
|
||||
doSomething;
|
||||
return true;
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current and next prayers with their names
|
||||
* @return {[adhan.PrayerTimes.prayer & string]} [currentPrayer, nextPrayer, currentName, nextName]
|
||||
*/
|
||||
function nextPrayer(){
|
||||
var now = new Date();
|
||||
var currentPrayer, nextPrayer, currentName, nextName;
|
||||
if (prayerTimes != undefined){
|
||||
if (now >= prayerTimes.isha){
|
||||
if (tomorrowPrayers == undefined){
|
||||
calcTomorrowPrayers();
|
||||
}
|
||||
currentPrayer = prayerTimes.isha;
|
||||
nextPrayer = tomorrowPrayers.fajr
|
||||
currentName = langIsha
|
||||
nextName = langFajr
|
||||
}
|
||||
else if (now >= prayerTimes.maghrib){
|
||||
currentPrayer = prayerTimes.maghrib;
|
||||
nextPrayer = prayerTimes.isha;
|
||||
currentName = langMaghrib
|
||||
nextName = langIsha
|
||||
}
|
||||
else if (now >= prayerTimes.asr){
|
||||
currentPrayer = prayerTimes.asr;
|
||||
nextPrayer = prayerTimes.maghrib;
|
||||
currentName = langAsr
|
||||
nextName = langMaghrib
|
||||
}
|
||||
else if (now >= prayerTimes.dhuhr){
|
||||
currentPrayer = prayerTimes.dhuhr;
|
||||
nextPrayer = prayerTimes.asr;
|
||||
currentName = langDhuhr
|
||||
nextName = langAsr
|
||||
}
|
||||
else if (now >= prayerTimes.fajr){
|
||||
currentPrayer = prayerTimes.fajr;
|
||||
nextPrayer = prayerTimes.dhuhr;
|
||||
currentName = langFajr
|
||||
nextName = langDhuhr
|
||||
}
|
||||
else{
|
||||
currentPrayer = prayerTimes.fajr;
|
||||
nextPrayer = prayerTimes.fajr;
|
||||
currentName = langFajr
|
||||
nextName = langFajr
|
||||
}
|
||||
}
|
||||
|
||||
return [currentPrayer, nextPrayer, currentName, nextName]
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the prayer is defined, returns the [hours, minutes, seconds] before/after the prayer
|
||||
* @param {adhan.PrayerTimes} prayer
|
||||
* @return {Numer[]} time
|
||||
*/
|
||||
function timeUntilPrayer(prayer) {
|
||||
var now = new Date()
|
||||
if (prayer != undefined){
|
||||
return msToTime(prayer - now);
|
||||
}
|
||||
else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts miliseconds to [hours, minutes, seconds]
|
||||
* @param {Number} duration
|
||||
* @return {Numer[]} res
|
||||
*/
|
||||
function msToTime(duration){ //https://stackoverflow.com/questions/19700283/how-to-convert-time-in-milliseconds-to-hours-min-sec-format-in-javascript
|
||||
var seconds = Math.floor((duration / 1000) % 60) + 1,
|
||||
minutes = Math.floor((duration / (1000 * 60)) % 60),
|
||||
hours = Math.floor((duration / (1000 * 60 * 60)) % 24);
|
||||
var res = [hours, minutes, seconds]
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
//checks if the app is being launched for the first time and if so, get location from location api
|
||||
function checkFirstTime(){
|
||||
var first = !store.has("first")
|
||||
if (first){
|
||||
var IPGeolocationAPI = require('ip-geolocation-api-javascript-sdk');
|
||||
|
||||
// Create IPGeolocationAPI object. Constructor takes two parameters.
|
||||
var ipgeolocationApi = new IPGeolocationAPI("b9aed80a71d043149013540fb449a384", false);
|
||||
|
||||
//var GeolocationParams = require('ip-geolocation-api-javascript-sdk/GeolocationParams.js');
|
||||
|
||||
// Get complete geolocation for the calling machine's IP address
|
||||
ipgeolocationApi.getGeolocation(handleResponse);
|
||||
|
||||
// Function to handle response from IP Geolocation API
|
||||
function handleResponse(json) {
|
||||
loadDefaultCalcMethod(json["continent_code"], json["country_code2"])
|
||||
store.set('latitude', json["latitude"])
|
||||
store.set('longitude', json["longitude"])
|
||||
store.set('timezone', json["time_zone"]["name"])
|
||||
//loadSettings()
|
||||
store.set('first', false)
|
||||
loadSettings()
|
||||
mainWindow.webContents.send('update');
|
||||
}
|
||||
}
|
||||
|
||||
//Looks at the continent and country of the user and chooses a calculation method
|
||||
function loadDefaultCalcMethod(continentCode, countryCode){
|
||||
if (countryCode == "RU"){
|
||||
|
||||
store.set('calculationMethod.calcMethod', "Russia");
|
||||
}
|
||||
else if (countryCode == "GB"){
|
||||
store.set('calculationMethod.calcMethod', "ISNA");
|
||||
}
|
||||
if (countryCode == "SG"){
|
||||
store.set('calculationMethod.calcMethod', "Singapore");
|
||||
}
|
||||
else if (countryCode == "QA"){
|
||||
store.set('calculationMethod.calcMethod', "Qatar");
|
||||
}
|
||||
else if (countryCode == "TR"){
|
||||
store.set('calculationMethod.calcMethod', "Turkey");
|
||||
}
|
||||
else if (countryCode == "IR"){
|
||||
store.set('calculationMethod.calcMethod', "Tehran");
|
||||
}
|
||||
else if (countryCode == "KW"){
|
||||
store.set('calculationMethod.calcMethod', "Kuwait");
|
||||
}
|
||||
else if (countryCode == "AE"){
|
||||
store.set('calculationMethod.calcMethod', "Dubai");
|
||||
}
|
||||
else if (countryCode == "PK"){
|
||||
store.set('calculationMethod.calcMethod', "Karachi");
|
||||
}
|
||||
else if (countryCode == "EG"){
|
||||
store.set('calculationMethod.calcMethod', "Egyptian");
|
||||
}
|
||||
else if (countryCode == "SA"){
|
||||
store.set('calculationMethod.calcMethod', "UAQ");
|
||||
|
||||
}
|
||||
else{
|
||||
switch (continentCode){
|
||||
case "NA": //N America
|
||||
|
||||
store.set('calculationMethod.calcMethod', "ISNA");
|
||||
|
||||
break;
|
||||
case "AF": //Africa
|
||||
break;
|
||||
case "EU": //EuropeD
|
||||
store.set('calculationMethod.calcMethod', "MWL");
|
||||
break;
|
||||
case "AS": //Asia
|
||||
store.set('calculationMethod.calcMethod', "ISNA");
|
||||
break;
|
||||
case "SA": //S America
|
||||
store.set('calculationMethod.calcMethod', "MWL");
|
||||
break;
|
||||
case "OC": //Oceania
|
||||
store.set('calculationMethod.calcMethod', "MWL");
|
||||
break;
|
||||
case "AN": //Antartica
|
||||
store.set('calculationMethod.calcMethod', "MC");
|
||||
break;
|
||||
default:
|
||||
store.set('calculationMethod.calcMethod', "MWL");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function loadLang(){
|
||||
langFajr = language.loadTrans(lang, 'fajr')
|
||||
langSunrise = language.loadTrans(lang, 'sunrise')
|
||||
langDhuhr = language.loadTrans(lang, 'dhuhr')
|
||||
langAsr= language.loadTrans(lang, 'asr')
|
||||
langMaghrib = language.loadTrans(lang, 'maghrib')
|
||||
langIsha = language.loadTrans(lang, 'isha')
|
||||
langAdhan = language.loadTrans(lang, 'adhan')
|
||||
langNow = language.loadTrans(lang, 'now')
|
||||
}
|
||||
|
||||
|
||||
function setAutoStart(autoStart){
|
||||
if(autoStart){
|
||||
// Checking if autoLaunch is enabled, if not then enabling it.
|
||||
autoLauncher.isEnabled().then(function(isEnabled) {
|
||||
if (isEnabled) return;
|
||||
autoLauncher.enable();
|
||||
}).catch(function (err) {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
else{
|
||||
if (autoLauncher.isEnabled()){
|
||||
try {
|
||||
autoLauncher.disable();
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/main/preload.js
Normal file
@@ -0,0 +1,22 @@
|
||||
// All of the Node.js APIs are available in the preload process.
|
||||
// It has the same sandbox as a Chrome extension.
|
||||
|
||||
const { contextBridge, ipcRenderer} = require('electron')
|
||||
const adhan = require('adhan')
|
||||
const settings = require('../common/common.js')
|
||||
const language = require('../common/language.js')
|
||||
const shell = require('electron').shell
|
||||
|
||||
contextBridge.exposeInMainWorld( 'api', {
|
||||
send: ( channel, data ) => ipcRenderer.invoke( channel, data ),
|
||||
handle: ( channel, func) => ipcRenderer.on( channel, (event, ...args) => func(...args) ),
|
||||
coordinates: (lat, lon) => adhan.Coordinates(lat, lon),
|
||||
getFromStore: (key, def) => ipcRenderer.invoke('getStoreValue', key, def),
|
||||
setToStore: (key, value) => ipcRenderer.invoke('setStoreValue', key , value),
|
||||
setTheme: (darkmode, css) => settings.toggleDarkMode(darkmode, css),
|
||||
getLanguage: (lang, value) => language.loadTrans(lang, value),
|
||||
getSunnah: (prayerTimes) => new adhan.SunnahTimes(prayerTimes),
|
||||
getPrayerTimes: (coordinates, date, parameters) => new adhan.PrayerTimes(coordinates, date, parameters),
|
||||
openExternal: (link) => shell.openExternal(link)
|
||||
})
|
||||
|
||||
699
src/main/renderer.js
Normal file
@@ -0,0 +1,699 @@
|
||||
// This file is required by the index.html file and will
|
||||
// be executed in the renderer process for that window.
|
||||
// No Node.js APIs are available in this process because
|
||||
// `nodeIntegration` is turned off. Use `preload.js` to
|
||||
// selectively enable features needed in the rendering
|
||||
// process.
|
||||
|
||||
var lat = 0;
|
||||
var lon = 0;
|
||||
|
||||
var timezone, timeFormat, shortTimeFormat, clockDisplay, lang;
|
||||
|
||||
var prayerTimes, calPrayers, tommorowPrayers, sunnahTimes;
|
||||
var datePick, volume;
|
||||
var loadedUI = false;
|
||||
var langFajr, langSunrise, langDhuhr, langMaghrib, langIsha, langAdhan, langNow, langTimeUntil;
|
||||
var sunnahTimes, motnCheckOG, totnCheckOG, totn, motn;
|
||||
var athanPlaying = false;
|
||||
var weatherSettings;
|
||||
|
||||
|
||||
var loaded = true;
|
||||
var event1 = new Event('loadedSettings')
|
||||
var event2 = new Event('loadedUI')
|
||||
loadHandles()
|
||||
loadSettings()
|
||||
|
||||
window.api.send('prayers');
|
||||
|
||||
|
||||
window.addEventListener('loadedSettings', () => {
|
||||
datePick = document.getElementById('calendar');
|
||||
getTomorrowPrayers()
|
||||
loadClock();
|
||||
loadHijriDate();
|
||||
loadCalendar()
|
||||
loadPrayers()
|
||||
volumeSlider()
|
||||
loadBackgroundImage()
|
||||
setKeyPress()
|
||||
setupButtonListeners()
|
||||
setupUpdateModal()
|
||||
setupWeather()
|
||||
|
||||
const interval = setInterval(function() {
|
||||
loadClock()
|
||||
loadNextPrayer()
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
window.addEventListener('loadedUI', () => {
|
||||
loadedUI = true;
|
||||
hideLoader()
|
||||
})
|
||||
|
||||
|
||||
function loadClock(){
|
||||
document.getElementById("clock").innerText = changeclockDisplay(new Date, timeFormat)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changes the format of the Date to a string (hours)
|
||||
* @param {Date} date
|
||||
* @param {String} timeformat
|
||||
*/
|
||||
|
||||
function changeclockDisplay(date, timeformat){
|
||||
if (timeformat[0] == 'H'){
|
||||
if (timeformat[6] == 's'){
|
||||
return show0(date.getHours()) + ":" + show0(date.getMinutes()) + ":" + show0(date.getSeconds())
|
||||
}
|
||||
return show0(date.getHours()) + ":" + show0(date.getMinutes())
|
||||
}
|
||||
else{
|
||||
let amPm = date.getHours() < 12 ? 'am' : 'pm'
|
||||
if (amPm == 'am'){
|
||||
if (timeformat[6] == 's'){
|
||||
return show0(date.getHours()) + ":" + show0(date.getMinutes()) + ":" + show0(date.getSeconds()) + ' AM'
|
||||
}
|
||||
return show0(date.getHours()) + ":" + show0(date.getMinutes()) + ' AM'
|
||||
}
|
||||
else{
|
||||
if (timeformat[6] == 's'){
|
||||
return show0(date.getHours() - 12) + ":" + show0(date.getMinutes()) + ":" + show0(date.getSeconds()) + ' PM'
|
||||
}
|
||||
return show0(date.getHours() - 12) + ":" + show0(date.getMinutes()) + ' PM'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Int} number
|
||||
* @returns A string of the 0 + number if it is < than 12
|
||||
*/
|
||||
function show0(number){
|
||||
let res
|
||||
number < 10 ? res = "0" + number.toString() : res = number.toString()
|
||||
return res
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function loadHijriDate(){
|
||||
var hijri = true;
|
||||
document.getElementById("dateLoc").innerText = (new Date).toLocaleDateString(lang,
|
||||
{ weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }).capitalize()
|
||||
hijri = true;
|
||||
setInterval(function() {
|
||||
if (hijri){
|
||||
document.getElementById("dateLoc").innerText = new Intl.DateTimeFormat(lang + '-TN-u-ca-islamic',
|
||||
{day: 'numeric', month: 'long',weekday: 'long',year : 'numeric'}).format(Date.now()).capitalize();
|
||||
hijri = false;
|
||||
}
|
||||
else{
|
||||
if (lang == "ur"){
|
||||
document.getElementById("dateLoc").innerText = ((new Date).toLocaleDateString("ar",
|
||||
{ weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })).capitalize()
|
||||
}
|
||||
else{
|
||||
document.getElementById("dateLoc").innerText = ((new Date).toLocaleDateString(lang,
|
||||
{ weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })).capitalize()
|
||||
}
|
||||
hijri = true;
|
||||
};
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
Object.defineProperty(String.prototype, 'capitalize', {
|
||||
value: function() {
|
||||
var upperCaseString = ''
|
||||
for (let i = 0; i < this.length; i ++){
|
||||
if (this.charAt(i) == ' ' && i != this.length-1){
|
||||
upperCaseString += ' ' + this.charAt(i+1).toUpperCase();
|
||||
i++
|
||||
}
|
||||
else{
|
||||
upperCaseString += this.charAt(i)
|
||||
}
|
||||
}
|
||||
res = upperCaseString.charAt(0).toUpperCase() + upperCaseString.slice(1);
|
||||
return res
|
||||
},
|
||||
enumerable: false
|
||||
});
|
||||
|
||||
//Picks the date from the calendar and adds a listener to the calendar, when the dates changes it sends a reuquest for time prayers.
|
||||
function loadCalendar(){
|
||||
Date.prototype.toDateInputValue = (function() {
|
||||
var local = new Date(this);
|
||||
local.setMinutes(this.getMinutes() - this.getTimezoneOffset());
|
||||
return local.toJSON().slice(0,10);
|
||||
});
|
||||
datePick.value = new Date().toDateInputValue();
|
||||
//window.api.send('date-request', datePick.value);
|
||||
datePick.addEventListener('change', function(){
|
||||
window.api.send('date-request', datePick.value);
|
||||
})
|
||||
}
|
||||
|
||||
//Load all the prayers of the day and shows them on the screen
|
||||
function loadPrayers(){
|
||||
if (datePick.value == new Date().toDateInputValue()){
|
||||
calPrayers = prayerTimes
|
||||
}
|
||||
if (calPrayers != undefined){
|
||||
document.getElementById("fajrTime").innerText = changeclockDisplay(convertTZ(calPrayers.fajr, timezone), shortTimeFormat);
|
||||
document.getElementById("sunriseTime").innerText = changeclockDisplay(convertTZ(calPrayers.sunrise, timezone), shortTimeFormat);
|
||||
document.getElementById("dhuhrTime").innerText = changeclockDisplay(convertTZ(calPrayers.dhuhr, timezone), shortTimeFormat);
|
||||
document.getElementById("asrTime").innerText = changeclockDisplay(convertTZ(calPrayers.asr, timezone), shortTimeFormat);
|
||||
document.getElementById("maghribTime").innerText = changeclockDisplay(convertTZ(calPrayers.maghrib, timezone), shortTimeFormat);
|
||||
document.getElementById("ishaTime").innerText = changeclockDisplay(convertTZ(calPrayers.isha, timezone), shortTimeFormat);
|
||||
if (sunnahTimes.totn && totn != undefined){
|
||||
document.getElementById("totnTime").innerText = changeclockDisplay(convertTZ(totn, timezone), shortTimeFormat);
|
||||
}
|
||||
if (sunnahTimes.motn && motn != undefined){
|
||||
document.getElementById("motnTime").innerText = changeclockDisplay(convertTZ(motn, timezone), shortTimeFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function convertTZ(date, tzString) {
|
||||
return new Date((typeof date === "string" ? new Date(date) : date).toLocaleString("en-US", {timeZone: tzString}));
|
||||
}
|
||||
|
||||
//Checks the store for saved settings, or gets default values
|
||||
async function loadSettings(){
|
||||
lat = await window.api.getFromStore('latitude', 0.00);
|
||||
lon = await window.api.getFromStore('longitude', 0.00);
|
||||
timezone = await window.api.getFromStore('timezone', 'US/Central');
|
||||
lang = await window.api.getFromStore('language', "en");
|
||||
volume = await window.api.getFromStore('volume', 50)
|
||||
|
||||
darkmode = await window.api.getFromStore('darkMode', false)
|
||||
window.api.setTheme(darkmode, "styles.css");
|
||||
|
||||
sunnahTimes = await window.api.getFromStore("sunnahTimes", {
|
||||
motn: false,
|
||||
totn: false
|
||||
})
|
||||
|
||||
motnCheckOG = sunnahTimes.motn; totnCheckOG = sunnahTimes.totn;
|
||||
|
||||
weatherSettings = await window.api.getFromStore('weather', {
|
||||
enabled: true,
|
||||
unit: "C"
|
||||
})
|
||||
loadLang()
|
||||
await hidePlayer()
|
||||
await loadClockDisplay()
|
||||
window.dispatchEvent(event1)
|
||||
}
|
||||
|
||||
//Calculates time left until #prayer
|
||||
function timeUntilPrayer(prayer){
|
||||
var now = new Date();
|
||||
if (prayer === src_Prayer.Fajr) {
|
||||
if (now.getHours() < 12){
|
||||
return this.msToTime(this.fajr - now);
|
||||
}
|
||||
else{
|
||||
now.getHours()
|
||||
const today = new Date();
|
||||
const tomorrow = new Date();
|
||||
tomorrow.setDate(today.getDate() + 1);
|
||||
let tommorowPrayer = new PrayerTimes_PrayerTimes(this.coordinates, tomorrow, this.calculationParameters)
|
||||
return this.msToTime(tommorowPrayer.fajr - now)
|
||||
}
|
||||
} else if (prayer === src_Prayer.Sunrise) {
|
||||
return this.msToTime(this.sunrise - now);
|
||||
} else if (prayer === src_Prayer.Dhuhr) {
|
||||
return this.msToTime(this.dhuhr - now);
|
||||
} else if (prayer === src_Prayer.asr) {
|
||||
return this.msToTime(this.asr - now);
|
||||
} else if (prayer === src_Prayer.maghrib) {
|
||||
return this.msToTime(this.maghrib - now);
|
||||
} else if (prayer === src_Prayer.isha) {
|
||||
return this.msToTime(this.isha - now);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//Loads the next prayers text: Prayer X in Y time;
|
||||
function loadNextPrayer(){
|
||||
var prayers = nextPrayer();
|
||||
if (prayers[0] != undefined){
|
||||
var timeUntilCurrentPrayer = timeUntilPrayer(prayers[0])
|
||||
if (athanPlaying && timeUntilCurrentPrayer[0] == -1 && timeUntilCurrentPrayer[1] >= -5){
|
||||
document.getElementById("timeLeft").innerText = langAdhan
|
||||
}
|
||||
else if(timeUntilCurrentPrayer[0] == -1 && timeUntilCurrentPrayer[1] >= -10){ //-1 because math.floor
|
||||
document.getElementById("timeLeft").innerText = langNow + ": " + prayers[2];
|
||||
}
|
||||
else{
|
||||
var time = timeUntilPrayer(prayers[1])
|
||||
document.getElementById("timeLeft").innerText = langTimeUntil + " " + prayers[3] + ": " + intToHour(time);
|
||||
}
|
||||
if (!loadedUI){
|
||||
window.dispatchEvent(event2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function nextPrayer(){
|
||||
var now = new Date();
|
||||
var currentPrayer, nextPrayer, currentName, nextName;
|
||||
if (prayerTimes != undefined && langFajr != undefined){
|
||||
if (now >= prayerTimes.isha){
|
||||
currentPrayer = prayerTimes.isha;
|
||||
nextPrayer = tommorowPrayers.fajr
|
||||
currentName = langIsha
|
||||
nextName = langFajr
|
||||
}
|
||||
else if (now >= prayerTimes.maghrib){
|
||||
currentPrayer = prayerTimes.maghrib;
|
||||
nextPrayer = prayerTimes.isha;
|
||||
currentName = langMaghrib
|
||||
nextName = langIsha
|
||||
}
|
||||
else if (now >= prayerTimes.asr){
|
||||
currentPrayer = prayerTimes.asr;
|
||||
nextPrayer = prayerTimes.maghrib;
|
||||
currentName = langAsr
|
||||
nextName = langMaghrib
|
||||
}
|
||||
else if (now >= prayerTimes.dhuhr){
|
||||
currentPrayer = prayerTimes.dhuhr;
|
||||
nextPrayer = prayerTimes.asr;
|
||||
currentName = langDhuhr
|
||||
nextName = langAsr
|
||||
}
|
||||
else if (now >= prayerTimes.fajr){
|
||||
currentPrayer = prayerTimes.fajr;
|
||||
nextPrayer = prayerTimes.dhuhr;
|
||||
|
||||
currentName = langFajr
|
||||
nextName = langDhuhr
|
||||
}
|
||||
else{
|
||||
currentPrayer = prayerTimes.fajr;
|
||||
nextPrayer = prayerTimes.fajr;
|
||||
currentName = langFajr
|
||||
nextName = langFajr
|
||||
}
|
||||
return [currentPrayer, nextPrayer, currentName, nextName]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function timeUntilPrayer(prayer) {
|
||||
var now = new Date()
|
||||
if (prayer != undefined){
|
||||
return msToTime(prayer - now);
|
||||
}
|
||||
else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function msToTime(duration){ //https://stackoverflow.com/questions/19700283/how-to-convert-time-in-milliseconds-to-hours-min-sec-format-in-javascript
|
||||
var seconds = Math.floor((duration / 1000) % 60) + 1,
|
||||
minutes = Math.floor((duration / (1000 * 60)) % 60),
|
||||
hours = Math.floor((duration / (1000 * 60 * 60)) % 24);
|
||||
if (seconds == 60){
|
||||
if (minutes == 0){
|
||||
minutes = 1;
|
||||
}
|
||||
seconds = 00;
|
||||
}
|
||||
var res = [hours, minutes, seconds]
|
||||
return res;
|
||||
}
|
||||
|
||||
function getTomorrowPrayers(){
|
||||
const today = new Date();
|
||||
const tomorrow = new Date();
|
||||
tomorrow.setDate(today.getDate() + 1);
|
||||
window.api.send('tomorrow-request', tomorrow);
|
||||
}
|
||||
|
||||
function intToHour(time){
|
||||
var hours = time[0];
|
||||
var minutes = time[1];
|
||||
var seconds = time[2];
|
||||
hours = (hours < 10) ? "0" + hours : hours;
|
||||
minutes = (minutes < 10) ? "0" + minutes : minutes;
|
||||
seconds = (seconds < 10) ? "0" + seconds : seconds;
|
||||
if (timeFormat[6] != 's' && (hours > 0 || minutes > 0)){
|
||||
return hours + ":" + minutes
|
||||
}
|
||||
else{
|
||||
return hours + ":" + minutes + ":" + seconds
|
||||
}
|
||||
}
|
||||
|
||||
function loadHandles(){
|
||||
window.api.handle('date-reply', msg => {
|
||||
calPrayers = msg;
|
||||
if (timezone != undefined){
|
||||
if (calPrayers.date.getDate() == new Date().getDate() && calPrayers.date.getMonth() == new Date().getMonth() && calPrayers.date.getFullYear() == new Date().getFullYear()){
|
||||
sunnahTimes.motn = motnCheckOG;
|
||||
sunnahTimes.totn = totnCheckOG;
|
||||
}
|
||||
else{
|
||||
sunnahTimes.motn = false;
|
||||
sunnahTimes.totn = false;
|
||||
}
|
||||
setupSunnah();
|
||||
loadPrayers();
|
||||
}
|
||||
})
|
||||
window.api.handle('prayersReply', msg => {
|
||||
prayerTimes = msg
|
||||
|
||||
nextPrayer()
|
||||
})
|
||||
window.api.handle('tomorrow-reply', msg => {
|
||||
tommorowPrayers = msg
|
||||
setupSunnah()
|
||||
})
|
||||
window.api.handle('progress-reply', msg => {
|
||||
athanPlaying = msg;
|
||||
})
|
||||
|
||||
window.api.handle('update', msg => {
|
||||
loadSettings()
|
||||
window.api.send('prayers', "Send me the times please");
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//Loads time format (for now date format does nothing)
|
||||
async function loadClockDisplay(){
|
||||
var clockDisplay = await window.api.getFromStore("timeDisplay", {
|
||||
clockFormat: 12,
|
||||
dateFormat: 'DD/MM/YYYY',
|
||||
showSeconds: true
|
||||
})
|
||||
|
||||
timeFormat = "hh:mm"
|
||||
if (clockDisplay.showSeconds){
|
||||
timeFormat += ":ss"
|
||||
}
|
||||
if (clockDisplay.clockFormat == 12){
|
||||
timeFormat += " A"
|
||||
}
|
||||
else{
|
||||
timeFormat = timeFormat.replace("hh", 'HH')
|
||||
}
|
||||
shortTimeFormat = timeFormat.replace(":ss", "")
|
||||
}
|
||||
|
||||
|
||||
//Sets event listeners and IPCRenderers to make volume sliders work
|
||||
function volumeSlider(){
|
||||
var volSlider = document.getElementById('volSlider');
|
||||
volSlider.value = volume
|
||||
volSlider.addEventListener('pointermove', function(){
|
||||
window.api.send('volume-request', volSlider.value);
|
||||
})
|
||||
volSlider.addEventListener('change', function(){
|
||||
window.api.send('volume-request', volSlider.value);
|
||||
window.api.setToStore('volume', volSlider.value)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//Hides the media player in case the Adhan is disabled
|
||||
async function hidePlayer(){
|
||||
var enableAdhan = await window.api.getFromStore('adhanCheck', true)
|
||||
if (!enableAdhan){
|
||||
document.getElementById('audioControls').style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If a bgImage is set in the settings, it gets applied, otherwise it disables the shaders
|
||||
*/
|
||||
async function loadBackgroundImage(){
|
||||
var bgImage = await window.api.getFromStore('bgImage', [true, '../../ressources/images/bgImage.jpg'])
|
||||
if (bgImage[0]){
|
||||
document.body.style.backgroundImage = "url('" + bgImage[1] + "')";
|
||||
}
|
||||
else{
|
||||
var shaders = document.getElementsByClassName("shader")
|
||||
for (let element of shaders){
|
||||
element.style.backgroundColor = "transparent"
|
||||
}
|
||||
document.body.style.backgroundImage = "none";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*Adds listener that brings you to the settings page when you press "Crtl + O"
|
||||
*/
|
||||
function setKeyPress(){
|
||||
var crtl = false;
|
||||
document.addEventListener('keydown', function(key){
|
||||
if (key.ctrlKey){
|
||||
crtl = true;
|
||||
}
|
||||
if ((key.key == "o" || key.key == "O") && crtl){
|
||||
window.location.assign("../settings/settings.html");
|
||||
}
|
||||
})
|
||||
document.addEventListener('keyup', function(key){
|
||||
if (key.ctrlKey){
|
||||
crtl = false;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function hideLoader(){
|
||||
document.getElementById('loader').style.display = "none"
|
||||
}
|
||||
|
||||
function loadLang(){
|
||||
langFajr = window.api.getLanguage(lang, 'fajr')
|
||||
langSunrise = window.api.getLanguage(lang, 'sunrise')
|
||||
langDhuhr = window.api.getLanguage(lang, 'dhuhr')
|
||||
langAsr= window.api.getLanguage(lang, 'asr')
|
||||
langMaghrib = window.api.getLanguage(lang, 'maghrib')
|
||||
langIsha = window.api.getLanguage(lang, 'isha')
|
||||
langAdhan = window.api.getLanguage(lang, 'adhan')
|
||||
langNow = window.api.getLanguage(lang, 'now')
|
||||
langTimeUntil = window.api.getLanguage(lang, 'timeUntil')
|
||||
document.getElementById('fajr').innerText = langFajr
|
||||
document.getElementById('sunrise').innerText = langSunrise
|
||||
document.getElementById('dhuhr').innerText = langDhuhr
|
||||
document.getElementById('asr').innerText = langAsr
|
||||
document.getElementById('maghrib').innerText = langMaghrib
|
||||
document.getElementById('isha').innerText = langIsha
|
||||
document.getElementById('settingsWheel').innerHTML = '<i class="fa fa-cog" aria-hidden="true"></i> ' + window.api.getLanguage(lang, 'settings')
|
||||
document.getElementById('motn').innerText = window.api.getLanguage(lang, 'motn')
|
||||
document.getElementById('totn').innerText = window.api.getLanguage(lang, 'totn')
|
||||
document.getElementById('quranButton').innerHTML = '<i class="fa-solid fa-book-quran"></i> ' + window.api.getLanguage(lang, 'quran')
|
||||
}
|
||||
|
||||
function setupButtonListeners(){
|
||||
document.getElementById('playB').addEventListener("click", function(){
|
||||
window.api.send("play");
|
||||
})
|
||||
document.getElementById('stopB').addEventListener("click", function(){
|
||||
window.api.send("stop");
|
||||
})
|
||||
document.getElementById('settingsWheel').addEventListener("click", function(){
|
||||
window.api.send("settingsO");
|
||||
window.location.href = "../settings/settings.html";
|
||||
})
|
||||
document.getElementById('quranButton').addEventListener("click", function(){
|
||||
window.location.href = "../quran/quran.html";
|
||||
})
|
||||
}
|
||||
|
||||
function setupSunnah(){
|
||||
if (prayerTimes != undefined && tommorowPrayers != undefined){
|
||||
|
||||
if (sunnahTimes.motn || sunnahTimes.totn){
|
||||
calculateSunnah()
|
||||
document.getElementById("box").style.marginTop = "0"
|
||||
if (sunnahTimes.motn && sunnahTimes.totn) document.getElementById("clock").style.marginTop = "1vh";
|
||||
else document.getElementById("clock").style.marginTop = "3vh";
|
||||
}
|
||||
else {
|
||||
document.getElementById("clock").style.marginTop = "4vh"
|
||||
document.getElementById("box").style.marginTop = "2vh"
|
||||
}
|
||||
|
||||
var motnDiv = document.getElementsByClassName("motn");
|
||||
if (sunnahTimes.motn){
|
||||
for (element of motnDiv){
|
||||
element.style.display = "block"
|
||||
}
|
||||
}
|
||||
else{
|
||||
for (element of motnDiv){
|
||||
element.style.display = "none"
|
||||
}
|
||||
}
|
||||
|
||||
var totnDiv = document.getElementsByClassName("totn");
|
||||
if (sunnahTimes.totn){
|
||||
for (element of totnDiv){
|
||||
element.style.display = "block"
|
||||
}
|
||||
}
|
||||
else{
|
||||
for (element of totnDiv){
|
||||
element.style.display = "none"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function calculateSunnah(){
|
||||
const nightDuration = (tommorowPrayers.fajr.getTime() - prayerTimes.maghrib.getTime());
|
||||
//motn = intToHour(msToTime(prayerTimes.maghrib.getTime() + nightDuration / 2));
|
||||
//totn = intToHour(msToTime(prayerTimes.maghrib.getTime() + nightDuration * (2 / 3);
|
||||
motn = new Date(prayerTimes.maghrib.getTime() + nightDuration / 2);
|
||||
totn = new Date(prayerTimes.maghrib.getTime() + nightDuration * (2 / 3));
|
||||
if (sunnahTimes.totn || sunnahTimes.motn){
|
||||
loadPrayers()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets up the update availible modal
|
||||
*/
|
||||
function setupUpdateModal(){
|
||||
var myModal = new bootstrap.Modal(document.getElementById('updateModal'), {
|
||||
})
|
||||
|
||||
var modalButton1 = document.getElementById('modalButton1')
|
||||
var modalButton2 = document.getElementById('modalButton2')
|
||||
var modalClose = document.getElementById('modalClose')
|
||||
|
||||
window.api.handle('update-available', msg => {
|
||||
/*modalTitle.innerText = window.api.getLanguage(lang, 'updateAvalible')
|
||||
modalBody.innerText = window.api.getLanguage(lang, 'downloadSoon')
|
||||
modalButton1.innerText = window.api.getLanguage(lang, 'ok')*/
|
||||
|
||||
document.getElementById("updateModalLabel").innerText = window.api.getLanguage(lang, 'updateAvailable')
|
||||
document.getElementById('modalBody').innerText = window.api.getLanguage(lang, 'version') + " " + msg[1] + " " + window.api.getLanguage(lang, 'available')
|
||||
modalButton1.innerText = window.api.getLanguage(lang, 'download')
|
||||
modalButton2.innerText = window.api.getLanguage(lang, 'later')
|
||||
|
||||
modalButton1.addEventListener("click", function(){
|
||||
window.api.openExternal("https://github.com/DBChoco/Muezzin/releases/latest")
|
||||
})
|
||||
modalButton2.addEventListener("click", function(){
|
||||
myModal.hide()
|
||||
})
|
||||
modalClose.addEventListener("click", function(){
|
||||
myModal.hide()
|
||||
})
|
||||
|
||||
myModal.show()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the weather is enabled, if so, sends api request and shows weather.
|
||||
* Then starts a timer that reloads the weather every 15m
|
||||
*/
|
||||
async function setupWeather(){
|
||||
if (weatherSettings.enabled){
|
||||
let units, system;
|
||||
switch (weatherSettings.units){
|
||||
case "K":
|
||||
units = "°K"
|
||||
system = "standard"
|
||||
break;
|
||||
case "F":
|
||||
units = "°F"
|
||||
system = "imperial"
|
||||
break;
|
||||
default:
|
||||
units = "°C"
|
||||
system = "metric"
|
||||
}
|
||||
await getWeather(units, system);
|
||||
setInterval(await getWeather(units, system), 900000) // 15min
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends api request for weather
|
||||
* @param {*} units
|
||||
* @param {*} system
|
||||
*/
|
||||
async function getWeather(units, system){
|
||||
try{
|
||||
response = await fetch('https://api.openweathermap.org/data/2.5/weather?lat=' + lat + '&lon=' + lon + '&units=' + system + '&appid=d8c0aa0e61cf524575a92e44d457ded7', {method: "GET"})
|
||||
.then(res => res.json())
|
||||
.then((json) => {
|
||||
console.debug("Loading weather")
|
||||
let time
|
||||
json["weather"][0]["icon"].charAt(json["weather"][0]["icon"].length - 1) == 'd' ? time = "day" : time = "night"
|
||||
|
||||
document.getElementById("weatherTemp").innerHTML = loadWeatherIcon(json["weather"][0]["id"], time) + " " + Math.round(json["main"]["temp"]) + units
|
||||
});
|
||||
}catch(e){
|
||||
console.error("Error while loading weather => " + e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Int} weather Id of the weather situation
|
||||
* @param {String} time Day or night
|
||||
* @returns An HTML string which contains a weather icon
|
||||
*/
|
||||
async function setupWeather(){
|
||||
try{
|
||||
response = await fetch('https://api.openweathermap.org/data/2.5/weather?lat=' + lat + '&lon=' + lon + '&lang=' + lang + '&units=metric' + '&appid=d8c0aa0e61cf524575a92e44d457ded7', {method: "GET"})
|
||||
.then(res => res.json())
|
||||
.then((json) => {
|
||||
let time
|
||||
json["weather"][0]["icon"].charAt(json["weather"][0]["icon"].length - 1) == 'd' ? time = "day" : time = "night"
|
||||
document.getElementById("weatherTemp").innerHTML = loadWeatherIcon(json["weather"][0]["id"], time) + " " + Math.round(json["main"]["temp"]) + "°C"
|
||||
});
|
||||
}catch(e){
|
||||
console.error("Error while loading weather => " + e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function loadWeatherIcon(weather, time = "day"){
|
||||
if (weather == 210 || weather == 211 || weather == 212 || weather == 221) return '<i class="wi wi-lightning"></i>'
|
||||
else if (weather >= 200 && weather <= 232) return '<i class="wi wi-storm-showers"></i>'
|
||||
else if (weather >= 300 && weather < 321) return '<i class="wi wi-rain"></i>'
|
||||
else if (weather >= 500 && weather <= 504) return '<i class="wi wi-rain"></i>'
|
||||
else if (weather == 511) return '<i class="wi wi-snowflake-cold'
|
||||
else if (weather >= 520 && weather <= 531) return '<i class="wi wi-showers"></i>'
|
||||
else if (weather >= 600 && weather <= 622) return '<i class="wi wi-snow"></i>'
|
||||
|
||||
else if (weather == 701 || weather == 741) return '<i class="wi wi-fog"></i>'
|
||||
else if (weather == 711 || weather == 731 || weather == 751 || weather == 761) return '<i class="wi wi-dust"></i>'
|
||||
else if (weather == 721) return '<i class="wi wi-smog"></i>'
|
||||
else if ( weather == 771 || weather == 781 || weather == 900) return '<i class="wi wi-tornado"></i>'
|
||||
|
||||
else if (weather == 762) return '<i class="wi wi-volcano"></i>'
|
||||
else if (weather == 800 || weather == 951){
|
||||
if (time == "day") return '<i class="wi wi-day-sunny"></i>'
|
||||
else return '<i class="wi wi-night-clear"></i>'
|
||||
}
|
||||
else if (weather == 801){
|
||||
if (time == "day") return '<i class="wi wi-day-cloudy"></i>'
|
||||
else return '<i class="wi wi-night-alt-cloudy"></i>'
|
||||
}
|
||||
else if (weather == 802) return '<i class="wi wi-cloud"></i>'
|
||||
else if (weather == 803) return '<i class="wi wi-cloudy"></i>'
|
||||
else if (weather == 804) return '<i class="wi wi-cloudy"></i>'
|
||||
|
||||
else return '<i class="wi wi-na"></i>'
|
||||
}
|
||||
161
src/main/styles.css
Normal file
@@ -0,0 +1,161 @@
|
||||
/* styles.css */
|
||||
header{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
|
||||
body{
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.shader{
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
#main{
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
#clock{
|
||||
font-size: 10vh;
|
||||
margin-top: 4vh;
|
||||
}
|
||||
|
||||
#title{
|
||||
font-size: 3vh;
|
||||
margin: 5px 0 0 5px;
|
||||
}
|
||||
|
||||
|
||||
#weatherContainer{
|
||||
font-size: 3vh;
|
||||
margin: 0px 10px 0 auto;
|
||||
|
||||
}
|
||||
|
||||
#dateLoc{
|
||||
font-size: 3vh;
|
||||
margin-bottom: 5vh;
|
||||
}
|
||||
|
||||
#timeLeft{
|
||||
font-size: 6vh;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
margin: auto;
|
||||
margin-bottom: 1vh;
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
width: 48vh;
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
border-top: 1px solid ;
|
||||
border-bottom: 1px solid;
|
||||
padding: 5px;
|
||||
font-size: 3vh;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.grid-top{
|
||||
border-top: 2px solid;
|
||||
}
|
||||
.grid-bottom{
|
||||
border-bottom: 2px solid;
|
||||
}
|
||||
|
||||
.left{
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.right{
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.box-bottom{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.box{
|
||||
margin: auto 0 auto 0;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#calendar{
|
||||
height: max(25px, 3vh);
|
||||
font-size: max(12px, 1.5vh);
|
||||
}
|
||||
|
||||
#buttons{
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
#settingsWheel , #quranButton{
|
||||
margin: 10px;
|
||||
font-size: max(1.8vh, 15px);
|
||||
}
|
||||
|
||||
#stopB, #playB{
|
||||
margin: 10px;
|
||||
font-size: max(1.5vh, 15px);
|
||||
}
|
||||
|
||||
#volume{
|
||||
margin-left: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: x-large;
|
||||
}
|
||||
|
||||
#mainContainer{
|
||||
width: fit-content;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 3vh auto 5vh auto;
|
||||
|
||||
}
|
||||
|
||||
.form-range{
|
||||
width: 100px;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
#audioControls, #upperPart{
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#volSlider{
|
||||
margin: 0px 10px 0px 10px;
|
||||
}
|
||||
|
||||
.center{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
background-color: #212121;
|
||||
display: -webkit-flexbox;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-flex-align: center;
|
||||
-ms-flex-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-light, .btn-light:hover{
|
||||
color: #212121;
|
||||
}
|
||||
12
src/mediaPlayer/mediaPlayer.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'">
|
||||
<title>MediaPlayer</title>
|
||||
</head>
|
||||
<body>
|
||||
MEDIA
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
11
src/mediaPlayer/preload.js
Normal file
@@ -0,0 +1,11 @@
|
||||
// All of the Node.js APIs are available in the preload process.
|
||||
// It has the same sandbox as a Chrome extension.
|
||||
|
||||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
|
||||
|
||||
contextBridge.exposeInMainWorld( 'api', {
|
||||
send: ( channel, data ) => ipcRenderer.invoke( channel, data ),
|
||||
handle: ( channel, func) => ipcRenderer.on( channel, (event, ...args) => func(...args) ),
|
||||
getFromStore: (key) => ipcRenderer.invoke('getStoreValue', key),
|
||||
})
|
||||
75
src/mediaPlayer/renderer.js
Normal file
@@ -0,0 +1,75 @@
|
||||
|
||||
|
||||
var athan = new Audio('../../ressources/audio/azan3.mp3');
|
||||
var dua = new Audio('../../ressources/audio/dua.mp3');
|
||||
var playDua = true;
|
||||
var interval;
|
||||
|
||||
var volume;
|
||||
|
||||
loadSettings()
|
||||
|
||||
setUpHandlers()
|
||||
|
||||
async function loadSettings(){
|
||||
volume = await window.api.getFromStore('volume', 50)
|
||||
athan.volume = volume/100
|
||||
dua.volume = volume/100
|
||||
}
|
||||
|
||||
function setUpHandlers(){
|
||||
window.api.handle('volume-reply', msg => {
|
||||
athan.volume = msg/100
|
||||
dua.volume = msg/100
|
||||
})
|
||||
window.api.handle('play', msg => {
|
||||
if (!athan.paused || !dua.paused){
|
||||
stop()
|
||||
}
|
||||
playDua = msg[2]
|
||||
athan = new Audio(msg[1]);
|
||||
setUpAdhanListeners()
|
||||
athan.play();
|
||||
})
|
||||
window.api.handle('stop', msg => {
|
||||
stop()
|
||||
})
|
||||
|
||||
window.api.send('startup-request');
|
||||
window.api.handle('startup-reply', msg => {
|
||||
if (msg == true){
|
||||
var bismillah = new Audio('../../ressources/audio/Bismillah - Fatih Sefaragic.mp3');
|
||||
bismillah.volume = volume/100;
|
||||
bismillah.play()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function stop(){
|
||||
athan.pause();
|
||||
athan.load();
|
||||
dua.pause();
|
||||
dua.load();
|
||||
}
|
||||
|
||||
function setUpAdhanListeners(){
|
||||
athan.addEventListener('ended', function(){
|
||||
window.api.send('progress-request', false)
|
||||
if (playDua){
|
||||
dua.play();
|
||||
}
|
||||
clearInterval(interval)
|
||||
})
|
||||
|
||||
athan.addEventListener('play', function(){
|
||||
loadSettings()
|
||||
window.api.send('progress-request', true)
|
||||
interval = setInterval(function(){
|
||||
window.api.send('progress-request', true)
|
||||
},5000)
|
||||
})
|
||||
athan.addEventListener('abort', function(){
|
||||
window.api.send('progress-request', false)
|
||||
clearInterval(interval)
|
||||
})
|
||||
}
|
||||
124
src/quran/quran.css
Normal file
@@ -0,0 +1,124 @@
|
||||
@import url("../../ressources/fonts/arabic/fonts.css");
|
||||
|
||||
header{
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#title{
|
||||
font-size: 8vh;
|
||||
margin: 2vh 0 4vh 0;
|
||||
}
|
||||
|
||||
#surahSelector{
|
||||
width: max-content;
|
||||
margin: 0 auto 0 auto;
|
||||
padding-bottom: 3vh;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.quranButton{
|
||||
display: flex;
|
||||
white-space: nowrap;
|
||||
margin: 0 20px 0 20px;
|
||||
}
|
||||
|
||||
#reader{
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: min(800px, 85vw);
|
||||
margin: 0 auto 0 auto;
|
||||
}
|
||||
|
||||
.verseContainer{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
border-top: 2px solid;
|
||||
}
|
||||
|
||||
.textContainer, .latinText{
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.word{
|
||||
padding: 5px 0px 5px 5px;
|
||||
}
|
||||
|
||||
.wordLatin{
|
||||
padding: 2px 2px 2px 0px;
|
||||
}
|
||||
|
||||
.arabText{
|
||||
text-align: right;
|
||||
font-size: 30px;
|
||||
margin: 30px;
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
flex-wrap: wrap;
|
||||
font-family: arabic;
|
||||
font-size: 42px;
|
||||
}
|
||||
|
||||
.arabicWord{
|
||||
font-family: arabic;
|
||||
font-size: 42px;
|
||||
}
|
||||
|
||||
.latinText{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 15px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.transText{
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.sidebar{
|
||||
width: fit-content;
|
||||
margin-right: 20px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.verseNumber{
|
||||
font-weight: bold;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.verse{
|
||||
width: 50%;
|
||||
height: max-content
|
||||
}
|
||||
|
||||
footer{
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#buttonContainer{
|
||||
margin: 0px 10px 10px auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#settings, #return{
|
||||
font-size: max(1.8vh, 15px);
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.bismillah{
|
||||
font-family: arabic-symbols;
|
||||
font-size: 22vmin;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.btn-light, .btn-light:hover{
|
||||
color: #212121;
|
||||
}
|
||||
61
src/quran/quran.html
Normal file
@@ -0,0 +1,61 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self'; style-src 'self' 'unsafe-inline'">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="../../node_modules/bootstrap-dark-5/dist/css/bootstrap-night.min.css" rel="stylesheet" >
|
||||
<script src="../../node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||
<link href="../../ressources/fonts/FontAwesome/all.min.css" rel="stylesheet" >
|
||||
<link href="quran.css" rel="stylesheet">
|
||||
<script src="quran.js"></script>
|
||||
<title>Muezzin</title>
|
||||
</head>
|
||||
<header>
|
||||
<h1 id="title">
|
||||
Qur'an
|
||||
</h1>
|
||||
</header>
|
||||
<body class="d-flex flex-column min-vh-100">
|
||||
|
||||
|
||||
<div id="surahSelector">
|
||||
|
||||
<button class="btn btn-dark quranButton" id="previousSurah">
|
||||
Previous Surah
|
||||
</button>
|
||||
|
||||
<select class="form-control" id="chaptersList">
|
||||
</select>
|
||||
|
||||
<button class="btn btn-dark quranButton" id="nextSurah">
|
||||
Next Surah
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="reader">
|
||||
<div class="bismillah">
|
||||
U
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<footer class="mt-auto fixed-bottom">
|
||||
<div id="buttonContainer">
|
||||
<button class="btn btn-dark" id="toTheTop">
|
||||
<i class="fa-solid fa-angles-up"></i>
|
||||
</button>
|
||||
<button class="btn btn-dark" id="settings">
|
||||
<i class="fa-solid fa-gear"></i>
|
||||
Settings
|
||||
</button>
|
||||
<button class="btn btn-dark" id="return">
|
||||
<i class="fa fa-arrow-circle-left"></i>
|
||||
Return
|
||||
</button>
|
||||
</div>
|
||||
</footer>
|
||||
</html>
|
||||
256
src/quran/quran.js
Normal file
@@ -0,0 +1,256 @@
|
||||
var lang;
|
||||
var quran;
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
loadSettings()
|
||||
buttonListeners();
|
||||
loadQuranList();
|
||||
//Make initial greeter when no Surahs are loaded
|
||||
//Add settings
|
||||
setupPreviousNextButtons()
|
||||
})
|
||||
|
||||
//Generates the div for 1 single verse.
|
||||
//Calls the functio to generate the arabText as well
|
||||
function generateVerse(number, arabText){
|
||||
let verseContainer = createDiv("verseContainer")
|
||||
|
||||
var sidebarDiv = createDiv("sidebar")
|
||||
var verseNumberDiv = createDiv("verseNumber")
|
||||
var textContainerDiv = createDiv("textContainer")
|
||||
var arabTextDiv = createDiv("arabText")
|
||||
|
||||
verseNumberDiv.innerHTML = number;
|
||||
|
||||
generateArabText(arabTextDiv, arabText, number.split(":")[1])
|
||||
|
||||
sidebarDiv.appendChild(verseNumberDiv)
|
||||
textContainerDiv.appendChild(arabTextDiv)
|
||||
|
||||
textContainerDiv.id = "textContainer" + number
|
||||
|
||||
verseContainer.appendChild(sidebarDiv)
|
||||
verseContainer.appendChild(textContainerDiv)
|
||||
|
||||
document.getElementById("reader").appendChild(verseContainer)
|
||||
}
|
||||
|
||||
|
||||
//Takes the div and the text, divides the text into divs and puts them into the mother div
|
||||
function generateArabText(arabTextDiv, arabText, verseNumber){
|
||||
var arabWords = arabText.split(" ");
|
||||
for (let word of arabWords){
|
||||
wordDiv = document.createElement("div");
|
||||
wordDiv.classList.add("word")
|
||||
wordDiv.classList.add("arabicWord")
|
||||
wordDiv.innerText = word;
|
||||
wordDiv.style.fontSize = quran.fontsize +"px";
|
||||
arabTextDiv.appendChild(wordDiv)
|
||||
}
|
||||
wordDiv = document.createElement("div");
|
||||
wordDiv.classList.add("word")
|
||||
wordDiv.innerText = new Intl.NumberFormat('ar-SA').format(verseNumber)
|
||||
wordDiv.style.fontSize = quran.fontsize +"px";
|
||||
arabTextDiv.appendChild(wordDiv)
|
||||
}
|
||||
|
||||
|
||||
//Loads the list of Surahs
|
||||
//TODO: Make it local.
|
||||
async function loadQuranList(){
|
||||
let chaptersList = document.getElementById("chaptersList")
|
||||
try{
|
||||
response = await fetch('../../ressources/quran/chapters.json')
|
||||
.then(res => res.json())
|
||||
.then((json) => {
|
||||
for (let chapter of json["chapters"]){
|
||||
var option = document.createElement("option")
|
||||
option.value = chapter["id"];
|
||||
option.innerText = "[" + chapter["id"] + "] " + chapter["name_simple"] + " - " + chapter["name_arabic"];
|
||||
chaptersList.appendChild(option)
|
||||
}
|
||||
chaptersList.addEventListener("change", function(){
|
||||
loadSurah(chaptersList.options[chaptersList.selectedIndex].value)
|
||||
})
|
||||
chaptersList.selectedIndex = -1
|
||||
});
|
||||
}catch(e){
|
||||
console.error("Error while loading list of Surahs" + e)
|
||||
}
|
||||
}
|
||||
|
||||
//When selecting a Surah, this is launched.
|
||||
//Calls the apis for the arabText, latins and translations and applies them.
|
||||
async function loadSurah(number){
|
||||
console.debug("Loading Surah n°" + number)
|
||||
document.getElementById("reader").innerHTML = ""
|
||||
var numberVerses = 0;
|
||||
try{
|
||||
response = await fetch('https://api.quran.com/api/v4/quran/verses/uthmani?chapter_number=' + number + '', {method: "GET"})
|
||||
.then(res => res.json())
|
||||
.then((json) => {
|
||||
for (let verse of json["verses"]){
|
||||
generateVerse(verse["verse_key"], verse["text_uthmani"])
|
||||
numberVerses ++;
|
||||
}
|
||||
});
|
||||
}catch(e){
|
||||
console.error("Couldn't load the Surah: " + e);
|
||||
}
|
||||
|
||||
var numberTranslated = 0;
|
||||
var page = 1;
|
||||
if (quran.transliteration.show || quran.translation.show){
|
||||
while (numberTranslated < numberVerses){
|
||||
try{
|
||||
response = await fetch('https://api.quran.com/api/v4/verses/by_chapter/' + number + '?language='+ quran.translation.lang +
|
||||
'&words=true&translations=' + quran.translation.trans + '&page=' + page, {method: "GET"})
|
||||
.then(res => res.json())
|
||||
.then((json) => {
|
||||
for (let verse of json["verses"]){
|
||||
if (quran.transliteration.show){
|
||||
addLatinText(verse)
|
||||
}
|
||||
if (quran.translation.show){
|
||||
addTranslation(verse)
|
||||
}
|
||||
numberTranslated ++;
|
||||
}
|
||||
page++
|
||||
});
|
||||
}catch(e){
|
||||
console.error("Couldn't load the translation: " + e)
|
||||
break; //If the user switches Surahs too fast, this saves lives.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Takes a verse made up of words and adds them separatly to the verseContainer
|
||||
//Possibility to add mouseOver events later on.
|
||||
function addLatinText(verse){
|
||||
var textContainerDiv = document.getElementById("textContainer" + verse["verse_key"])
|
||||
var latinTextDiv = createDiv("latinText")
|
||||
|
||||
for (let word of verse["words"]){
|
||||
var wordDiv = document.createElement("div")
|
||||
wordDiv.classList.add("wordLatin")
|
||||
wordDiv.innerText = word["transliteration"]["text"]
|
||||
latinTextDiv.appendChild(wordDiv)
|
||||
}
|
||||
latinTextDiv.style.fontSize = quran.transliteration.fontsize + "px";
|
||||
textContainerDiv.appendChild(latinTextDiv)
|
||||
}
|
||||
|
||||
|
||||
//Takes a verse and loads the translation to the textContainerDiv
|
||||
function addTranslation(verse){
|
||||
var textContainerDiv = document.getElementById("textContainer" + verse["verse_key"])
|
||||
var transTextDiv = createDiv("transText")
|
||||
transTextDiv.innerHTML = verse["translations"][0]["text"]
|
||||
transTextDiv.style.fontSize = quran.translation.fontsize + "px";
|
||||
textContainerDiv.appendChild(transTextDiv)
|
||||
}
|
||||
|
||||
|
||||
//Creates a div with the class name = divClass
|
||||
function createDiv(divClass){
|
||||
var divv = document.createElement("div");
|
||||
divv.classList.add(divClass);
|
||||
return divv;
|
||||
}
|
||||
|
||||
//Loads all the necessary settings
|
||||
async function loadSettings(){
|
||||
lang = await window.api.getFromStore('language', 'en')
|
||||
translate()
|
||||
|
||||
quran = await window.api.getFromStore('quran', {
|
||||
fontsize: 42,
|
||||
translation:{
|
||||
show: true,
|
||||
lang: {
|
||||
enabled: false,
|
||||
lang: "en"
|
||||
},
|
||||
trans: 131,
|
||||
fontsize: 14
|
||||
},
|
||||
transliteration:{
|
||||
show: true,
|
||||
fontsize: 14
|
||||
},
|
||||
})
|
||||
|
||||
var darkmode = await window.api.getFromStore('darkMode', false)
|
||||
window.api.setTheme(darkmode, "quran.css");
|
||||
}
|
||||
|
||||
function buttonListeners(){
|
||||
document.getElementById("settings").addEventListener("click", function(){
|
||||
window.location.assign("../settings/settings.html?page=quran");
|
||||
})
|
||||
|
||||
document.getElementById("return").addEventListener("click", function(){
|
||||
window.location.assign("../main/index.html");
|
||||
})
|
||||
|
||||
document.getElementById("toTheTop").addEventListener("click", function(){
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
})
|
||||
}
|
||||
|
||||
//Does not work yet, I'll have to work on this one.
|
||||
function downloadOrFetch(link, path, filename){
|
||||
var absolutePath = appDataPath + path
|
||||
var file = new File(absolutePath + filename)
|
||||
|
||||
if (file.exists()){
|
||||
console.log("yes")
|
||||
}
|
||||
|
||||
else{
|
||||
window.api.send("download", {
|
||||
url: link,
|
||||
properties: {
|
||||
directory: absolutePath,
|
||||
filename: filename
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function translate(){
|
||||
document.getElementById("title").innerHTML = window.api.getLanguage(lang, "quran");
|
||||
document.getElementById("settings").innerHTML = '<i class="fa-solid fa-gear"></i> ' + window.api.getLanguage(lang, "settings");
|
||||
document.getElementById("return").innerHTML = '<i class="fa fa-arrow-circle-left"></i> ' + window.api.getLanguage(lang, "return");
|
||||
}
|
||||
|
||||
function setupPreviousNextButtons(){
|
||||
let chapterList = document.getElementById("chaptersList")
|
||||
let previous = document.getElementById("previousSurah")
|
||||
let next = document.getElementById("nextSurah")
|
||||
chapterList.addEventListener("change", function(){
|
||||
previous.disabled = false;
|
||||
next.disabled = false;
|
||||
if (chaptersList.options[chaptersList.selectedIndex].value == 1){
|
||||
previous.disabled = true;
|
||||
} else if (chaptersList.options[chaptersList.selectedIndex].value == 114){
|
||||
next.disabled = true;
|
||||
}
|
||||
})
|
||||
|
||||
previous.addEventListener("click", function(){
|
||||
if (!previous.disabled){
|
||||
chapterList.selectedIndex -= 1;
|
||||
chapterList.dispatchEvent(new Event('change'))
|
||||
}
|
||||
})
|
||||
|
||||
next.addEventListener("click", function(){
|
||||
if (!next.disabled){
|
||||
chapterList.selectedIndex += 1;
|
||||
chapterList.dispatchEvent(new Event('change'))
|
||||
}
|
||||
})
|
||||
}
|
||||
151
src/settings/settings.css
Normal file
@@ -0,0 +1,151 @@
|
||||
#settingsTitle{
|
||||
padding: 30px;
|
||||
font-size: 72px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.grid-itemL {
|
||||
text-align: left;
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.grid-itemR {
|
||||
width: fit-content;
|
||||
margin-left: auto;
|
||||
text-align: right;
|
||||
align-items: right;
|
||||
padding-bottom: 15px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.grid-R-spacer{
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.grid-itemR-S {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.grid-sub{
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
.colorLabel{
|
||||
text-align: right;
|
||||
padding-left: auto;
|
||||
}
|
||||
|
||||
#v-pills-tab{
|
||||
border-style: none solid none none ;
|
||||
border-width: 2px;
|
||||
padding-right: 20px;
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
/* Style the button that is used to open and close the collapsible content */
|
||||
.collapsible {
|
||||
cursor: pointer;
|
||||
padding: 18px;
|
||||
width: 100%;
|
||||
border: none;
|
||||
text-align: left;
|
||||
outline: none;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
|
||||
/*Pill color*/
|
||||
.nav-pills .nav-link.active {
|
||||
background-color: #212121
|
||||
}
|
||||
|
||||
/*Font Color*/
|
||||
.nav-link{
|
||||
color: black;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover)
|
||||
.active, .collapsible:hover {
|
||||
}*/
|
||||
|
||||
/* Style the collapsible content. Note: hidden by default */
|
||||
.content {
|
||||
padding: 0 18px;
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#v-pills-tabContent{
|
||||
width: 65%;
|
||||
}
|
||||
|
||||
#return{
|
||||
font-size: max(1.8vh, 15px);
|
||||
margin: 0px 10px 10px auto;
|
||||
}
|
||||
|
||||
.container{
|
||||
max-width: 900px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-bottom: auto;
|
||||
}
|
||||
|
||||
.image{
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
/*Pill color*/
|
||||
.light-pills .light-link.active {
|
||||
background-color: #212121
|
||||
}
|
||||
|
||||
/*Font Color*/
|
||||
.light-link{
|
||||
color: black;
|
||||
}
|
||||
|
||||
/*Pill color*/
|
||||
.dark-pills .dark-link.active {
|
||||
background-color: #adb5bd;
|
||||
color: #212121
|
||||
}
|
||||
|
||||
/*Font Color*/
|
||||
.dark-link{
|
||||
color: white;
|
||||
}
|
||||
|
||||
/*Hover color
|
||||
.nav-link:hover {
|
||||
color: pink;
|
||||
}*/
|
||||
|
||||
.btn-light, .btn-light:hover{
|
||||
color: #212121;
|
||||
}
|
||||
|
||||
#citation{
|
||||
text-align: center;
|
||||
margin:auto 10% auto 10%
|
||||
}
|
||||
|
||||
footer{
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.shortInput{
|
||||
width: 100px;
|
||||
margin-left: auto;
|
||||
}
|
||||
603
src/settings/settings.html
Normal file
@@ -0,0 +1,603 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self'; style-src 'self' 'unsafe-inline'">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="../../node_modules/bootstrap-dark-5/dist/css/bootstrap-night.min.css" rel="stylesheet" >
|
||||
<script src="../../node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||
<link href="../../ressources/fonts/FontAwesome/all.min.css" rel="stylesheet" >
|
||||
<link href="settings.css" rel="stylesheet">
|
||||
<script src="settings.js"></script>
|
||||
<title>Muezzin</title>
|
||||
</head>
|
||||
<body class="d-flex flex-column min-vh-100">
|
||||
<h1 id=settingsTitle>Settings</h1>
|
||||
<div id="settingsContainer" class="container">
|
||||
<div class="d-flex align-items-start">
|
||||
<div class="nav flex-column nav-pills me-3" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
||||
<button class="nav-link active" id="v-pills-general-tab" data-bs-toggle="pill" data-bs-target="#v-pills-general" type="button" role="tab" aria-controls="v-pills-general" aria-selected="true">
|
||||
General
|
||||
</button>
|
||||
<button class="nav-link" id="v-pills-location-tab" data-bs-toggle="pill" data-bs-target="#v-pills-location" type="button" role="tab" aria-controls="v-pills-location" aria-selected="false">
|
||||
Location
|
||||
</button>
|
||||
<button class="nav-link" id="v-pills-audio-tab" data-bs-toggle="pill" data-bs-target="#v-pills-audio" type="button" role="tab" aria-controls="v-pills-audio" aria-selected="false">Audio</button>
|
||||
<button class="nav-link" id="v-pills-appearance-tab" data-bs-toggle="pill" data-bs-target="#v-pills-appearance" type="button" role="tab" aria-controls="v-pills-appearance" aria-selected="false">Appearance</button>
|
||||
<button class="nav-link" id="v-pills-advanced-tab" data-bs-toggle="pill" data-bs-target="#v-pills-advanced" type="button" role="tab" aria-controls="v-pills-advanced" aria-selected="false">Advanced</button>
|
||||
<button class="nav-link" id="v-pills-adjustments-tab" data-bs-toggle="pill" data-bs-target="#v-pills-adjustments" type="button" role="tab" aria-controls="v-pills-adjustments" aria-selected="false">Adjustments</button>
|
||||
<button class="nav-link" id="v-pills-quran-tab" data-bs-toggle="pill" data-bs-target="#v-pills-quran" type="button" role="tab" aria-controls="v-pills-quran" aria-selected="false">
|
||||
<i class="fa-solid fa-book-quran"></i>
|
||||
Qur'an
|
||||
</button>
|
||||
</div>
|
||||
<div class="tab-content" id="v-pills-tabContent">
|
||||
|
||||
<div class="tab-pane fade show active" id="v-pills-general" role="tabpanel" aria-labelledby="v-pills-general-tab"> <!-- General -->
|
||||
<div class="grid-container">
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="langText">Language </p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<form >
|
||||
<select class="form-select" id="langlist" name="Language">
|
||||
<option value="en">English</option>
|
||||
<option value="fr">Français</option>
|
||||
<option value="es">Español</option>
|
||||
<option value="it">Italiano</option>
|
||||
<option value="ar">عربي</option>
|
||||
<option value="de">Deutsch</option>
|
||||
<option value="nl">Nederlands</option>
|
||||
<option value="no">Norsk (bokmål)</option>
|
||||
<option value="sv">Svenska</option>
|
||||
<option value="da">Dansk</option>
|
||||
<option value="ur">Urdu</option>
|
||||
<option value="tr">Türkçe</option>
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="tfText">Time format</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<form >
|
||||
<div class="form-check">
|
||||
|
||||
<input class="form-check-input" type="radio" name="timeFormat" id="24hTimeFormat">
|
||||
<label class="form-check-label" for="24hTimeFormat" id="24hTimeFormatText">
|
||||
24 Hour
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="timeFormat" id="12hTimeFormat" checked>
|
||||
<label class="form-check-label" for="12hTimeFormat" id="12hTimeFormatText">
|
||||
12 Hour
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="" id="showSeconds" checked>
|
||||
<label class="form-check-label" for="showSeconds" id="showSecondsText">
|
||||
Show seconds
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="dfText">Date format</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<form >
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="dateFormat" id="dateFormat1" checked>
|
||||
<label class="form-check-label" for="dateFormat1" id="df1Text">
|
||||
DD/MM/YYYY
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="dateFormat" id="dateFormat2">
|
||||
<label class="form-check-label" for="dateFormat2" id="df2Text">
|
||||
MM/DD/YYYY
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="dateFormat" id="dateFormat3">
|
||||
<label class="form-check-label" for="dateFormat3" id="df3Text">
|
||||
YYYY/MM/DD
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="notifText">Notifications</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<form>
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="notifCheck" id="notifCheckText">
|
||||
Enable notifications
|
||||
</label>
|
||||
<input class="form-check-input" type="checkbox" id="notifCheck" checked>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="systrayText">System tray</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<form>
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="systrayCheck" id="systrayCheckText">
|
||||
Minimize to tray
|
||||
</label>
|
||||
<input class="form-check-input" type="checkbox" id="systrayCheck" checked>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="autoStartText">Auto Start</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<form>
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="autoStartCheck" id="autoStartCheckText">
|
||||
Start at launch
|
||||
</label>
|
||||
<input class="form-check-input" type="checkbox" id="autoStartCheck" checked>
|
||||
</div>
|
||||
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="minStartCheck" id="minStartCheckText">
|
||||
Start minimized
|
||||
</label>
|
||||
<input class="form-check-input" type="checkbox" id="minStartCheck" unchecked>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="v-pills-location" role="tabpanel" aria-labelledby="v-pills-location-tab"> <!-- Location -->
|
||||
<div class="grid-container">
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="coordinatesText">Coordinates</p>
|
||||
</div>
|
||||
<div class="grid-itemR grid-itemR-S">
|
||||
<label class="form-check-label" for="latInput" id="latText">
|
||||
Latitude
|
||||
</label>
|
||||
<input id="latInput" class="form-control" type="number" value="0.00" min="-90" max="90" step="0.1" maxlength="5"
|
||||
placeholder="00.00">
|
||||
</div>
|
||||
<div class="grid-itemL grid-sub">
|
||||
</div>
|
||||
<div class="grid-itemR grid-itemR-S">
|
||||
<label class="form-check-label" for="lonInput" id="lonText">
|
||||
Longitude
|
||||
</label>
|
||||
<input id="lonInput" class="form-control" type="number" value="0.00" min="-180" max="180" step="0.1"
|
||||
placeholder="00.00">
|
||||
</div>
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="tzText">Time zone</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<form >
|
||||
<select class="form-select" id="tzlist" name="TimeZone"></select>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="v-pills-audio" role="tabpanel" aria-labelledby="v-pills-audio-tab"> <!-- Audio -->
|
||||
<div class="grid-container">
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="adhanText">Adhan </p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<form >
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="adhanCheck" id="adhanCheckText">
|
||||
Enable Adhan
|
||||
</label>
|
||||
<input class="form-check-input" type="checkbox" id="adhanCheck" unchecked>
|
||||
</div>
|
||||
|
||||
<div class="grid-R-spacer">
|
||||
<select class="form-select" id="adhanList" name="adhanList">
|
||||
<option id="adhanMecca" value="../../ressources/audio/Adhan - Mecca.mp3" id="adhanMeccaText">Adhan Mecca</option>
|
||||
<option id="adhanAqsa" value="../../ressources/audio/Adhan - al-Aqsa.mp3" id="adhanAqsaText">Adhan al-Aqsa</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="customAdhan" id="customAdhanText">
|
||||
Custom Adhan
|
||||
</label>
|
||||
<input class="form-check-input" type="checkbox" id="customAdhan" checked>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<input class="form-control" type="file" id="customAdhanFile" accept="audio/*,.mp3, .ogg, .wav">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="duaAfterText">Du'a after Adhan</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<div class="gform-check grid-R-spacer">
|
||||
<input class="form-check-input" type="checkbox" value="" id="duaCheck" checked>
|
||||
<label class="form-check-label" for="duaCheck" id="duaCheckText">
|
||||
Play Du'a after Adhan
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="startUpSoundText">Start Up Sound</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<form>
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="startUpSound" id="startUpSoundText2">
|
||||
Play sound on startup
|
||||
</label>
|
||||
<input class="form-check-input" type="checkbox" id="startUpSound" checked>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="v-pills-appearance" role="tabpanel" aria-labelledby="v-pills-appearance-tab"> <!-- Appearance -->
|
||||
<div class="grid-container">
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="themeText">Theme</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="darkModeCheck" id="darkModeText">Enable Dark Mode</label>
|
||||
<input class="form-check-input" type="checkbox" value="" id="darkModeCheck" checked>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="bgImageText">Background Image</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<form >
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="bgImageCheck" id="bgImageCheckText">Enable Background Image</label>
|
||||
<input class="form-check-input" type="checkbox" value="" id="bgImageCheck" checked>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<input class="form-control" type="file" id="customBgImage" accept="image/*">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="sunnahTimesText">Show Sunnah times</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<form >
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="MOTNCheck" id="MOTNCheckText">Middle of the night</label>
|
||||
<input class="form-check-input" type="checkbox" value="" id="MOTNCheck" unchecked>
|
||||
</div>
|
||||
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="TOTNCheck" id="TOTNCheckText">Third of the night</label>
|
||||
<input class="form-check-input" type="checkbox" value="" id="TOTNCheck" unchecked>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="sunnahTimesText">Weather</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<form >
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="weatherCheck" id="weatherCheckText">Show weather</label>
|
||||
<input class="form-check-input" type="checkbox" value="" id="weatherCheck" checked>
|
||||
</div>
|
||||
|
||||
<div class="form-check grid-R-spacer">
|
||||
<form >
|
||||
<label class="form-check-label" for="unitList" id="unitListText">Units</label>
|
||||
<select class="form-select" id="unitList" name="units">
|
||||
<option value="C">Celcius</option>
|
||||
<option value="K">Kelvin</option>
|
||||
<option value="F">Fahrenheit</option>
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="v-pills-advanced" role="tabpanel" aria-labelledby="v-pills-advanced-tab"> <!-- Advanced -->
|
||||
<div class="grid-container">
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="calcMethodsText">Calculation Methods</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<form >
|
||||
<select class="form-select" id="calcMethodList" name="calcMethodList">
|
||||
<option id="MWL" value="MWL" selected>Muslim World League</option>
|
||||
<option id="Egyptian" value="Egyptian">Egyptian</option>
|
||||
<option id="Karachi" value="Karachi">Karachi</option>
|
||||
<option id="UAQ" value="UAQ">Umm al-Qura</option>
|
||||
<option id="Dubai" value="Dubai">Dubai</option>
|
||||
<option id="Qatar" value="Qatar">Qatar</option>
|
||||
<option id="Kuwait" value="Kuwait">Kuwait</option>
|
||||
<option id="MC" value="MC">Moonsighting Committee</option>
|
||||
<option id="Singapore" value="Singapore">Singapore</option>
|
||||
<option id="Turkey" value="Turkey">Turkey</option>
|
||||
<option id="Tehran" value="Tehran">Tehran</option>
|
||||
<option id="ISNA" value="ISNA">ISNA</option>
|
||||
<option id="France12" value="France12">France 12</option>
|
||||
<option id="France15" value="France15">France 15</option>
|
||||
<option id="France18" value="France18">France 18</option>
|
||||
<option id="Russia" value="Russia">Russia</option>
|
||||
<option id="Gulf" value="Gulf">Gulf Region</option>
|
||||
</select> <br>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="MadhabText">Madhab</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<select class="form-select" id="madhabList" name="madhabList">
|
||||
<option id="Shafi" value="Shafi" selected>Shafi</option>
|
||||
<option id="Hanafi" value="Hanafi">Hanafi</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="hlrText">High Latitude Rule</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<select class="form-select" id="highLatitudeRuleList" name="highLatitudeRuleList">
|
||||
<option id="MOTN" value="MOTN">Middle of the Night</option>
|
||||
<option id="SOTN" value="SOTN">Seventh of the Night</option>
|
||||
<option id="TA" value="TA" selected>Twilight Angle</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="grid-itemL" data-bs-toggle="tooltip" data-bs-placement="top" title="Tooltip on top">
|
||||
<p class="h4" id="pcrText">Polar Circle Resolution</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<select class="form-select" id="polarCircleResolutionList" name="polarCircleResolutionList">
|
||||
<option id="CC" value="CC" selected>Closest City</option>
|
||||
<option id="CD" value="CD">Closest Date</option>
|
||||
<option id="UND" value="UND">Do not calculate</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="ShafaqText">Shafaq</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<select class="form-select" id="shafaqList" name="shafaqList">
|
||||
<option id="shafaqG" value="shafaqG" selected>General</option>
|
||||
<option id="shafaqR" value="shafaqR">Red Twilight (ahmer)</option>
|
||||
<option id="shafaqW" value="shafaqW">White Twilight (abyad)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="customSettText">Custom settings</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<form>
|
||||
<div class="form-check">
|
||||
<label class="form-check-label" for="customCalcCheck" id="enableCalcText">
|
||||
Enable Custom Calculation Settings
|
||||
</label>
|
||||
<input class="form-check-input" type="checkbox" id="customCalcCheck" unchecked>
|
||||
</div>
|
||||
|
||||
|
||||
<label class="form-check-label" for="fajrAngle" id="fajrAngleText">
|
||||
Fajr Angle
|
||||
</label>
|
||||
<input id="fajrAngle" class="form-control shortInput" type="number" value="0.00" min="-90" max="90" step="0.1" maxlength="5"
|
||||
placeholder="00.00">
|
||||
|
||||
<label class="form-check-label" for="maghribAngle" id="maghribAngleText">
|
||||
Maghrib Angle
|
||||
</label>
|
||||
<input id="maghribAngle" class="form-control shortInput" type="number" value="0.00" min="-90" max="90" step="0.1" maxlength="5"
|
||||
placeholder="00.00">
|
||||
|
||||
<label class="form-check-label" for="ishaAngle" id="ishaAngleText">
|
||||
Isha Angle
|
||||
</label>
|
||||
<input id="ishaAngle" class="form-control shortInput" type="number" value="0.00" min="-90" max="90" step="0.1" maxlength="5"
|
||||
placeholder="00.00">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="grid-itemL">
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<form>
|
||||
<div class="form-check">
|
||||
<label class="form-check-label" for="delayCheck" id="delayText">
|
||||
Delay after Maghrib
|
||||
</label>
|
||||
<input class="form-check-input" type="checkbox" id="delayCheck" unchecked>
|
||||
</div>
|
||||
|
||||
<label class="form-check-label" for="ishaAngle" id="delayFormText">
|
||||
Delay (minutes)
|
||||
</label>
|
||||
<input id="delayForm" class="form-control shortInput" type="number" value="0" min="0" max="300" step="1" maxlength="3"
|
||||
placeholder="00">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="v-pills-adjustments" role="tabpanel" aria-labelledby="v-pills-adjustments-tab"> <!-- Adjustements -->
|
||||
<div class="grid-container">
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="adjustmentsText">Adjustments</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<form >
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="adjCheck" id="adjCheckText">
|
||||
Enable adjustments
|
||||
</label>
|
||||
<input class="form-check-input" type="checkbox" id="adjCheck" unchecked>
|
||||
</div>
|
||||
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="fajrAdjInput" id="fajrAdjText">
|
||||
Fajr Adjustments
|
||||
</label>
|
||||
<input id="fajrAdjInput" class="form-control shortInput" type="number" value="0" min="-90" max="90" step="1" maxlength="5"
|
||||
placeholder="00.00">
|
||||
</div>
|
||||
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="dhuhrAdjInput" id="dhuhrAdjText">
|
||||
Dhuhr Adjustments
|
||||
</label>
|
||||
<input id="dhuhrAdjInput" class="form-control shortInput" type="number" value="0" min="-90" max="90" step="1" maxlength="5"
|
||||
placeholder="00.00">
|
||||
</div>
|
||||
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="asrAdjInput" id="asrAdjText">
|
||||
Asr Adjustments
|
||||
</label>
|
||||
<input id="asrAdjInput" class="form-control shortInput" type="number" value="0" min="-90" max="90" step="1" maxlength="5"
|
||||
placeholder="00.00">
|
||||
</div>
|
||||
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="maghribAdjInput" id="maghribAdjText">
|
||||
Maghrib Adjustments
|
||||
</label>
|
||||
<input id="maghribAdjInput" class="form-control shortInput" type="number" value="0" min="-90" max="90" step="1" maxlength="5"
|
||||
placeholder="00.00">
|
||||
</div>
|
||||
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="ishaAdjInput" id="ishaAdjText">
|
||||
Isha Adjustments
|
||||
</label>
|
||||
<input id="ishaAdjInput" class="form-control shortInput" type="number" value="0" min="-90" max="90" step="1" maxlength="5"
|
||||
placeholder="00.00">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="v-pills-quran" role="tabpanel" aria-labelledby="v-pills-quran-tab"> <!-- Qur'an -->
|
||||
<div class="grid-container">
|
||||
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="quranFontText">Font</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="quranFontSize" id="quranFontSizeText">
|
||||
Font Size
|
||||
</label>
|
||||
<input id="quranFontSize" class="form-control shortInput" type="number" value="20" min="12" max="100" step="1" placeholder="20">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="translationText">Translation</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<div class=" grid-R-spacer">
|
||||
<input class="form-check-input" type="checkbox" id="showTranslationCheck" checked>
|
||||
<label class="form-check-label" for="showTranslationCheck" id="showTranslationCheckText">
|
||||
Show translation
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="grid-R-spacer">
|
||||
<input class="form-check-input" type="checkbox" id="quranLangCheck" unchecked>
|
||||
<label class="form-check-label" for="quranLangCheck" id="quranLangCheckText">
|
||||
Different language from app
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check grid-R-spacer">
|
||||
<form >
|
||||
<select class="form-select" id="quranLangList" name="quranLanguage">
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="form-check grid-R-spacer">
|
||||
<form >
|
||||
<select class="form-select" id="translationList" name="translationList">
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<label class="form-check-label" for="translationFontSize" id="translationFontSizeText">
|
||||
Font Size
|
||||
</label>
|
||||
<input id="translationFontSize" class="form-control shortInput" type="number" value="20" min="12" max="100" step="1" placeholder="20">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid-itemL">
|
||||
<p class="h4" id="transliterationText">Transliteration</p>
|
||||
</div>
|
||||
<div class="grid-itemR">
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="showTransliterationCheck" id="showTransliterationCheckText">
|
||||
Show transliteration
|
||||
</label>
|
||||
<input class="form-check-input" type="checkbox" id="showTransliterationCheck" checked>
|
||||
</div>
|
||||
|
||||
<div class="form-check grid-R-spacer">
|
||||
<label class="form-check-label" for="TransliterationFontSize" id="transliterationFontSizeText">
|
||||
Font Size
|
||||
</label>
|
||||
<input id="transliterationFontSize" class="form-control shortInput" type="number" value="20" min="12" max="100" step="1" placeholder="20">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<figure id="citation">
|
||||
<blockquote id="quote" class="blockquote" >
|
||||
<p>Indeed, prayer has been decreed upon the believers a decree of specified times.</p>
|
||||
</blockquote>
|
||||
<figcaption class="blockquote-footer">
|
||||
<cite id=source title="Source of quote">Qur'an: 4/103</cite>
|
||||
</figcaption>
|
||||
</figure>
|
||||
|
||||
</body>
|
||||
<footer class="mt-auto">
|
||||
<button class="btn btn-dark" id="return">Return</button>
|
||||
</footer>
|
||||
</html>
|
||||
944
src/settings/settings.js
Normal file
@@ -0,0 +1,944 @@
|
||||
var timeDisplay, language, adhanFile, bgImage;
|
||||
var lat,lon;
|
||||
var fromQuran = false;
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
loadSettings()
|
||||
setNumberLimit(document.getElementById("latInput"));
|
||||
setNumberLimit(document.getElementById("lonInput"));
|
||||
setTZlist();
|
||||
returnButton();
|
||||
addThemeListener()
|
||||
setKeyPress();
|
||||
addLangListener()
|
||||
loadQueryString()
|
||||
})
|
||||
|
||||
/**
|
||||
* Saves all settings to the store
|
||||
*/
|
||||
async function saveSettings(){
|
||||
await saveTimeDateFormat()
|
||||
//Values that might change too much should not be saved automaticaly (no saver)
|
||||
if (lat != document.getElementById("latInput").value) await window.api.setToStore('latitude', lat);
|
||||
if (lon != document.getElementById("lonInput").value) await window.api.setToStore('longitude', lon);
|
||||
await saveAdhan()
|
||||
await saveBgImage()
|
||||
await saveAdjustments()
|
||||
await saveCustomSettings()
|
||||
await saveQuran()
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all the settings from the store
|
||||
*/
|
||||
async function loadSettings(){
|
||||
lat = await window.api.getFromStore('latitude', 0.00);
|
||||
lon = await window.api.getFromStore('longitude', 0.00);
|
||||
var tzVal = await window.api.getFromStore('timezone', 'US/Central');
|
||||
var darkMode = await window.api.getFromStore('darkMode', false);
|
||||
language = await window.api.getFromStore('language', 'en');
|
||||
|
||||
var sunnahTimes = await window.api.getFromStore("sunnahTimes", {
|
||||
motn: false,
|
||||
totn: false
|
||||
})
|
||||
|
||||
timeDisplay = await window.api.getFromStore("timeDisplay", {
|
||||
clockFormat: 12,
|
||||
dateFormat: 'DD/MM/YYYY',
|
||||
showSeconds: true
|
||||
})
|
||||
|
||||
var settings = await window.api.getFromStore("settings", {
|
||||
startupSound: false,
|
||||
notifCheck: true,
|
||||
systray: true,
|
||||
adhanCheck: true,
|
||||
autoStart: true,
|
||||
minStart: false
|
||||
})
|
||||
|
||||
var weather = await window.api.getFromStore("weather", {
|
||||
enabled: true,
|
||||
units: "C"
|
||||
})
|
||||
|
||||
var calculationMethod = await window.api.getFromStore("calculationMethod", {
|
||||
calcMethod: 'MWL',
|
||||
madhab: 'Shafi',
|
||||
hlr: 'TA',
|
||||
pcr: 'CC',
|
||||
shafaq: 'shafaqG'
|
||||
})
|
||||
|
||||
await loadAdhan()
|
||||
await loadCustomSettings()
|
||||
await loadAdjustments()
|
||||
|
||||
document.getElementById("latInput").value = lat
|
||||
document.getElementById("lonInput").value = lon
|
||||
|
||||
//Selects the loaded value from the lists
|
||||
selectFromList(document.getElementById('langlist'), language)
|
||||
selectFromList(document.getElementById("tzlist"), tzVal)
|
||||
selectFromList(document.getElementById("calcMethodList"), calculationMethod.calcMethod)
|
||||
selectFromList(document.getElementById("madhabList"), calculationMethod.madhab)
|
||||
selectFromList(document.getElementById("highLatitudeRuleList"), calculationMethod.hlr)
|
||||
selectFromList(document.getElementById("polarCircleResolutionList"), calculationMethod.pcr)
|
||||
selectFromList(document.getElementById("shafaqList"), calculationMethod.shafaq)
|
||||
|
||||
await addSaverValue(document.getElementById("tzlist"), tzVal, "timezone")
|
||||
await addSaverValue(document.getElementById("calcMethodList"), calculationMethod.calcMethod, "calculationMethod.calcMethod")
|
||||
await addSaverValue(document.getElementById("madhabList"), calculationMethod.madhab, "calculationMethod.madhab")
|
||||
await addSaverValue(document.getElementById("highLatitudeRuleList"), calculationMethod.hlr, "calculationMethod.hlr")
|
||||
await addSaverValue(document.getElementById("polarCircleResolutionList"), calculationMethod.pcr, "calculationMethod.pcr")
|
||||
await addSaverValue(document.getElementById("shafaqList"), calculationMethod.shafaq, "calculationMethod.shafaq")
|
||||
|
||||
await addSaverValue(document.getElementById("langlist"), language, "language")
|
||||
await addSaverValue(document.getElementById("unitList"), weather.units, "weather.units")
|
||||
|
||||
await addSaverChecked(document.getElementById("darkModeCheck"), darkMode, 'darkMode')
|
||||
await addSaverChecked(document.getElementById("notifCheck"), settings.notifCheck, 'settings.notifCheck');
|
||||
await addSaverChecked(document.getElementById("adhanCheck"), settings.adhanCheck, 'settings.adhanCheck');
|
||||
await addSaverChecked(document.getElementById("systrayCheck"), settings.systray, 'settings.systray');
|
||||
await addSaverChecked(document.getElementById("startUpSound"), settings.startupSound, 'settings.startupSound');
|
||||
await addSaverChecked(document.getElementById("autoStartCheck"), settings.autoStart, 'settings.autoStart');
|
||||
await addSaverChecked(document.getElementById("minStartCheck"), settings.minStart, 'settings.minStart');
|
||||
await addSaverChecked(document.getElementById("MOTNCheck"), sunnahTimes.motn, 'sunnahTimes.motn');
|
||||
await addSaverChecked(document.getElementById("TOTNCheck"), sunnahTimes.totn, 'sunnahTimes.totn');
|
||||
await addSaverChecked(document.getElementById("showSeconds"), timeDisplay.showSeconds, "timeDisplay.showSeconds")
|
||||
await addSaverChecked(document.getElementById("weatherCheck"), weather.enabled, "weather.enabled")
|
||||
|
||||
window.api.setTheme(darkMode, "settings.css");
|
||||
setTimeDateFormat()
|
||||
disableAdhanListener()
|
||||
loadLanguage(language)
|
||||
loadBgImage()
|
||||
|
||||
await loadQuranSettings()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the element to the value and adds a listener
|
||||
* If the element changes, the value is directly sent to the store value (thanks to its name)
|
||||
*
|
||||
* @param element the UI element that gets the value and event listener.
|
||||
* @param value if this one is defined
|
||||
* @param name if this one is defined
|
||||
*/
|
||||
async function addSaverChecked(element, value, name){
|
||||
element.checked = value;
|
||||
element.addEventListener("change", async function(){
|
||||
await window.api.setToStore(name, element.checked)
|
||||
console.debug("Saved " + element.checked + " to store (from " + value + ")")
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the element to the value and adds a listener
|
||||
* If the element changes, the value is directly sent to the store value (thanks to its name)
|
||||
*
|
||||
* @param element the UI element that gets the value and event listener.
|
||||
* @param value if this one is defined
|
||||
* @param name if this one is defined
|
||||
*/
|
||||
async function addSaverValue(element, value, name){
|
||||
element.value = value;
|
||||
element.addEventListener("change", async function(){
|
||||
await window.api.setToStore(name, element.value)
|
||||
console.debug("Saved " + element.value + " to store (from " + value + ")")
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Saves and brings you back to index.html when you click on the retrn button (adds listener)
|
||||
*/
|
||||
async function returnButton(){
|
||||
var set = document.getElementById("return");
|
||||
set.onclick= async function(){
|
||||
await saveSettings()
|
||||
window.api.send("settingsC");
|
||||
if (!fromQuran){
|
||||
window.location.assign("../main/index.html");
|
||||
}
|
||||
else{
|
||||
window.location.assign("../quran/quran.html");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves and brings you back to index.html when you press the ESC key
|
||||
*/
|
||||
async function setKeyPress(){
|
||||
document.addEventListener('keydown', async function(key){
|
||||
console.debug("Pressed the: " + key.key + " key")
|
||||
if (key.key == "Escape"){
|
||||
await saveSettings()
|
||||
window.api.send("settingsC");
|
||||
window.location.assign("../main/index.html");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes you unable to type out of bounds for the lat and lon fields
|
||||
*/
|
||||
function setNumberLimit(){
|
||||
var latInput = document.getElementById("latInput");
|
||||
var latOldValue = latInput.value;
|
||||
latInput.addEventListener("focus", function(){
|
||||
latOldValue = latInput.value;
|
||||
});
|
||||
latInput.addEventListener("input", function(){
|
||||
if (latInput.value > 90 || latInput.value < -90 || latInput.value.length > 7){
|
||||
latInput.value = latOldValue;
|
||||
}
|
||||
else{
|
||||
latOldValue = latInput.value;
|
||||
}
|
||||
});
|
||||
|
||||
var lonInput = document.getElementById("lonInput");
|
||||
var lonOldValue = lonInput.value;
|
||||
lonInput.addEventListener("focus", function(){
|
||||
lonOldValue = lonInput.value;
|
||||
});
|
||||
lonInput.addEventListener("input", function(){
|
||||
if (lonInput.value > 180 || lonInput.value < -180 || lonInput.value.length > 7){
|
||||
lonInput.value = lonOldValue;
|
||||
}
|
||||
else{
|
||||
lonOldValue = lonInput.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all timezones, and adds them to the TZ list
|
||||
*/
|
||||
async function setTZlist(){
|
||||
const container = document.getElementById("tzlist");
|
||||
|
||||
response = await fetch('../../ressources/timezones.json')
|
||||
.then(res => res.json())
|
||||
.then((json) => {
|
||||
for (zone of json){
|
||||
for (timezone of zone["utc"]){
|
||||
var option = document.createElement("option")
|
||||
option.id = timezone;
|
||||
option.value = timezone;
|
||||
option.innerText = timezone;
|
||||
container.appendChild(option)
|
||||
}
|
||||
}
|
||||
sortSelect(container)
|
||||
})
|
||||
}
|
||||
|
||||
function sortSelect(selElem) { //Source https://stackoverflow.com/questions/278089/javascript-to-sort-contents-of-select-element
|
||||
var tmpAry = new Array();
|
||||
for (var i=0;i<selElem.options.length;i++) {
|
||||
tmpAry[i] = new Array();
|
||||
tmpAry[i][0] = selElem.options[i].text;
|
||||
tmpAry[i][1] = selElem.options[i].value;
|
||||
}
|
||||
tmpAry.sort();
|
||||
while (selElem.options.length > 0) {
|
||||
selElem.options[0] = null;
|
||||
}
|
||||
for (var i=0;i<tmpAry.length;i++) {
|
||||
var op = new Option(tmpAry[i][0], tmpAry[i][1]);
|
||||
selElem.options[i] = op;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Goes through the form/list and selects the val
|
||||
*/
|
||||
function selectFromList(list, val){
|
||||
list.childNodes.forEach(function(node){
|
||||
if (node.value == val){
|
||||
node.selected = true;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
//Looks at the checkboxes/radios and sets the variables according to the formats
|
||||
async function saveTimeDateFormat(){
|
||||
if (document.getElementById("24hTimeFormat").checked){
|
||||
timeDisplay.clockFormat = 24;
|
||||
}
|
||||
else {
|
||||
timeDisplay.clockFormat = 12;
|
||||
}
|
||||
if (document.getElementById("dateFormat1").checked){
|
||||
timeDisplay.dateFormat = "DD/MM/YYYY"
|
||||
}
|
||||
else if (document.getElementById("dateFormat2").checked){
|
||||
timeDisplay.dateFormat = "MM/DD/YYYY"
|
||||
}
|
||||
else{
|
||||
timeDisplay.dateFormat = "YYYY/MM/DD"
|
||||
}
|
||||
await window.api.setToStore('timeDisplay.clockFormat', timeDisplay.clockFormat);
|
||||
await window.api.setToStore('timeDisplay.dateFormat', timeDisplay.dateFormat);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* From the loaded values, checks and unchecks the time/formats checkboxes
|
||||
*/
|
||||
function setTimeDateFormat(){
|
||||
if (timeDisplay != undefined){
|
||||
document.getElementById("showSeconds").checked = timeDisplay.showSeconds;
|
||||
if (timeDisplay.clockFormat == 24){
|
||||
document.getElementById("24hTimeFormat").checked = true;
|
||||
} else{
|
||||
document.getElementById("12hTimeFormat").checked = true;
|
||||
}
|
||||
|
||||
if(timeDisplay.dateFormat == "DD/MM/YYYY"){
|
||||
document.getElementById("dateFormat1").checked = true;
|
||||
}else if ( dateFormat == "MM/DD/YYYY"){
|
||||
document.getElementById("dateFormat2").checked = true;
|
||||
}else{
|
||||
document.getElementById("dateFormat3").checked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If val is defined, change the value of the element to @val
|
||||
*
|
||||
* @param element the element gets the value
|
||||
* @param val if this one is defined
|
||||
*/
|
||||
function setSavedVal(element, val){
|
||||
if (val != undefined){
|
||||
element.value = val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads the custom/preset Adhan (bool, source path)
|
||||
*/
|
||||
async function loadAdhan(){
|
||||
adhanFile = await window.api.getFromStore('adhanFile', [false, "ressources/audio/Adhan - Mecca.mp3", true]);
|
||||
var customCheck = document.getElementById("customAdhan");
|
||||
customCheck.checked = adhanFile[0]
|
||||
var duaCheck = document.getElementById("duaCheck");
|
||||
duaCheck.checked = adhanFile[2]
|
||||
|
||||
if (!customCheck.checked){
|
||||
selectFromList(document.getElementById("adhanList"), adhanFile[1])
|
||||
}
|
||||
|
||||
setUpAdhan()
|
||||
customCheck.addEventListener('change', function(){
|
||||
setUpAdhan()
|
||||
})
|
||||
|
||||
document.getElementById("customAdhanFile").addEventListener("change", function(){
|
||||
var file = document.getElementById("customAdhanFile").files[0].path;
|
||||
console.debug("Loaded: " + file)
|
||||
})
|
||||
|
||||
|
||||
function setUpAdhan(){ //changes the states of the forms if custom adhans are enabled/disabled
|
||||
if (!customCheck.checked){
|
||||
document.getElementById("customAdhanFile").disabled = true;
|
||||
document.getElementById("adhanList").disabled = false;
|
||||
}
|
||||
else{
|
||||
document.getElementById("customAdhanFile").disabled = false;
|
||||
document.getElementById("adhanList").disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds listeners to the many Adhan checkboxes and disables them when they are not used
|
||||
*/
|
||||
function disableAdhanListener(){
|
||||
var adhanCheck = document.getElementById("adhanCheck")
|
||||
disableAdhan(adhanCheck)
|
||||
adhanCheck.addEventListener('change', function(){
|
||||
disableAdhan(adhanCheck)
|
||||
})
|
||||
|
||||
function disableAdhan(adhanCheck){
|
||||
if (!adhanCheck.checked){
|
||||
document.getElementById("customAdhanFile").disabled = true;
|
||||
document.getElementById("adhanList").disabled = true;
|
||||
document.getElementById("duaCheck").disabled = true;
|
||||
document.getElementById("customAdhan").disabled = true;
|
||||
}
|
||||
else{
|
||||
document.getElementById("duaCheck").disabled = false;
|
||||
document.getElementById("customAdhan").disabled = false;
|
||||
if (!document.getElementById("customAdhan").checked){
|
||||
document.getElementById("customAdhanFile").disabled = true;
|
||||
document.getElementById("adhanList").disabled = false;
|
||||
}
|
||||
else{
|
||||
document.getElementById("customAdhanFile").disabled = false;
|
||||
document.getElementById("adhanList").disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Saves Adhan values (bool, source)
|
||||
*/
|
||||
async function saveAdhan(){
|
||||
var customCheck = document.getElementById("customAdhan");
|
||||
var duaCheck = document.getElementById("duaCheck");
|
||||
var path;
|
||||
if (!customCheck.checked){
|
||||
path = document.getElementById("adhanList").value;
|
||||
}
|
||||
else {
|
||||
var file = document.getElementById("customAdhanFile").files
|
||||
if (file != undefined && file.length != 0){
|
||||
path = file[0].path;
|
||||
}
|
||||
else{
|
||||
path = adhanFile[1]
|
||||
}
|
||||
}
|
||||
adhanFile = [customCheck.checked, path, duaCheck.checked]
|
||||
await window.api.setToStore('adhanFile', adhanFile)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Event listener in case the darkmode check changes
|
||||
*/
|
||||
function addThemeListener(){
|
||||
var darkTheme = document.getElementById("darkModeCheck")
|
||||
darkTheme.addEventListener('change', function(){
|
||||
window.api.setTheme(darkTheme.checked, "settings.css");
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reloads the stylesheet if @param darkmode changes
|
||||
*
|
||||
* @param darkMode bool: if darkmode is enabled => true
|
||||
*/
|
||||
function toggleDarkMode(darkMode){
|
||||
var head = document.getElementsByTagName('HEAD')[0];
|
||||
var link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.type = 'text/css';
|
||||
if (darkMode){
|
||||
link.href = '../../node_modules/bootstrap-dark-5/dist/css/bootstrap-dark.css';
|
||||
//document.body.style.backgroundColor = "#0b5345 "
|
||||
}
|
||||
else{
|
||||
link.href = '../../node_modules/bootstrap/dist/css/bootstrap.css';
|
||||
//document.body.style.backgroundColor = "#85929e"
|
||||
}
|
||||
head.appendChild(link);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads the background values (bool, source), and if true, sets the background + an event listener
|
||||
*/
|
||||
async function loadBgImage(){
|
||||
bgImage = await window.api.getFromStore('bgImage', [true, '../../ressources/images/bgImage.jpg']);
|
||||
var bgImageCheck = document.getElementById("bgImageCheck")
|
||||
bgImageCheck.checked = bgImage[0];
|
||||
var file = document.getElementById("customBgImage")
|
||||
if (!bgImageCheck.checked ){
|
||||
file.disabled = true;
|
||||
}
|
||||
bgImageCheck.addEventListener('change', function(){
|
||||
if (!bgImageCheck.checked ){
|
||||
file.disabled = true;
|
||||
}
|
||||
else{
|
||||
file.disabled = false;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the background image values (bool, source)
|
||||
*/
|
||||
async function saveBgImage(){
|
||||
var bgImageCheck = document.getElementById("bgImageCheck").checked
|
||||
if (!bgImageCheck){
|
||||
await window.api.setToStore('bgImage', [false, '../../ressources/images/bgImage.jpg'])
|
||||
}
|
||||
else{
|
||||
var file = document.getElementById("customBgImage").files
|
||||
if (file != undefined && file.length != 0){
|
||||
await window.api.setToStore('bgImage', [true, file[0].path])
|
||||
}
|
||||
else{
|
||||
let darkmode = document.getElementById("darkModeCheck").checked
|
||||
if (darkmode && bgImage[1] == '../../ressources/images/bgImage.jpg'){
|
||||
await window.api.setToStore('bgImage', [true, '../../ressources/images/bgImage_dark.avif'])
|
||||
}
|
||||
else if (!darkmode && bgImage[1] == '../../ressources/images/bgImage_dark.avif'){
|
||||
await window.api.setToStore('bgImage', [true, '../../ressources/images/bgImage.jpg'])
|
||||
}
|
||||
else{
|
||||
await window.api.setToStore('bgImage', [true, bgImage[1]])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function addLangListener(){
|
||||
var langList = document.getElementById('langlist')
|
||||
langList.addEventListener('change', function(){
|
||||
loadLanguage(langList.value)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the innerTexts of all the elements in the page
|
||||
*
|
||||
* @param lang the language selected by the user
|
||||
*/
|
||||
function loadLanguage(lang){
|
||||
document.getElementById("v-pills-general-tab").innerHTML = '<i class="fa-solid fa-kaaba"></i> ' + window.api.getLanguage(lang, "general");
|
||||
document.getElementById("v-pills-location-tab").innerHTML = '<i class="fa-solid fa-location-dot"></i> ' + window.api.getLanguage(lang, "location");
|
||||
document.getElementById("v-pills-audio-tab").innerHTML = '<i class="fa-solid fa-volume-high"></i> ' + window.api.getLanguage(lang, "audio");
|
||||
document.getElementById("v-pills-appearance-tab").innerHTML = '<i class="fa-solid fa-palette"></i> ' + window.api.getLanguage(lang, "appearance");
|
||||
document.getElementById("v-pills-advanced-tab").innerHTML = '<i class="fa-solid fa-sliders"></i> ' + window.api.getLanguage(lang, "advanced");
|
||||
document.getElementById("v-pills-adjustments-tab").innerHTML = '<i class="fa-solid fa-clock"></i> ' + window.api.getLanguage(lang, "adjustements");
|
||||
document.getElementById("v-pills-quran-tab").innerHTML = '<i class="fa-solid fa-book-quran"></i> ' + window.api.getLanguage(lang, "quran");
|
||||
|
||||
document.getElementById("return").innerHTML = '<i class="fa fa-arrow-circle-left"></i> ' + window.api.getLanguage(lang, "return");
|
||||
|
||||
document.getElementById("langText").innerText = window.api.getLanguage(lang, "language");
|
||||
document.getElementById("settingsTitle").innerText = window.api.getLanguage(lang, "settings");
|
||||
document.getElementById("tfText").innerText = window.api.getLanguage(lang, "timeDisplay");
|
||||
document.getElementById("24hTimeFormatText").innerText = window.api.getLanguage(lang, "24hour");
|
||||
document.getElementById("12hTimeFormatText").innerText = window.api.getLanguage(lang, "12hour");
|
||||
document.getElementById("showSecondsText").innerText = window.api.getLanguage(lang, "showSseconds");
|
||||
document.getElementById("dfText").innerText = window.api.getLanguage(lang, "dateFormat");
|
||||
document.getElementById("df1Text").innerText = window.api.getLanguage(lang, "dateFormat1");
|
||||
document.getElementById("df2Text").innerText = window.api.getLanguage(lang, "dateFormat2");
|
||||
document.getElementById("df3Text").innerText = window.api.getLanguage(lang, "dateFormat3");
|
||||
document.getElementById("notifText").innerText = window.api.getLanguage(lang, "notifications");
|
||||
document.getElementById("notifCheckText").innerText = window.api.getLanguage(lang, "notifCheck");
|
||||
document.getElementById("coordinatesText").innerText = window.api.getLanguage(lang, "coordinates");
|
||||
document.getElementById("latText").innerText = window.api.getLanguage(lang, "latitude");
|
||||
document.getElementById("lonText").innerText = window.api.getLanguage(lang, "longitude");
|
||||
document.getElementById("tzText").innerText = window.api.getLanguage(lang, "timezone");
|
||||
document.getElementById("adhanText").innerText = window.api.getLanguage(lang, "adhan");
|
||||
document.getElementById("adhanCheckText").innerText = window.api.getLanguage(lang, "adhanCheck");
|
||||
//document.getElementById("adhanMeccaText").innerText = window.api.getLanguage(lang, "adhanMecca");
|
||||
//document.getElementById("adhanAqsaText").innerText = window.api.getLanguage(lang, "adhanAqsa");
|
||||
document.getElementById("customAdhanText").innerText = window.api.getLanguage(lang, "customAdhan");
|
||||
document.getElementById("duaAfterText").innerText = window.api.getLanguage(lang, "duaAfterAdhan");
|
||||
document.getElementById("themeText").innerText = window.api.getLanguage(lang, "theme");
|
||||
document.getElementById("darkModeText").innerText = window.api.getLanguage(lang, "darkMode");
|
||||
document.getElementById("bgImageText").innerText = window.api.getLanguage(lang, "bgImage");
|
||||
document.getElementById("bgImageCheckText").innerText = window.api.getLanguage(lang, "bgImageCheck");
|
||||
document.getElementById("calcMethodsText").innerText = window.api.getLanguage(lang, "calcMethods");
|
||||
document.getElementById("MWL").innerText = window.api.getLanguage(lang, "mwl");
|
||||
document.getElementById("Egyptian").innerText = window.api.getLanguage(lang, "egyptian");
|
||||
document.getElementById("Karachi").innerText = window.api.getLanguage(lang, "karachi");
|
||||
document.getElementById("UAQ").innerText = window.api.getLanguage(lang, "uaq");
|
||||
document.getElementById("Dubai").innerText = window.api.getLanguage(lang, "dubai");
|
||||
document.getElementById("Qatar").innerText = window.api.getLanguage(lang, "qatar");
|
||||
document.getElementById("Kuwait").innerText = window.api.getLanguage(lang, "kuwait");
|
||||
document.getElementById("MC").innerText = window.api.getLanguage(lang, "mc");
|
||||
document.getElementById("Singapore").innerText = window.api.getLanguage(lang, "singapore");
|
||||
document.getElementById("Turkey").innerText = window.api.getLanguage(lang, "turkey");
|
||||
document.getElementById("Tehran").innerText = window.api.getLanguage(lang, "tehran");
|
||||
document.getElementById("ISNA").innerText = window.api.getLanguage(lang, "isna");
|
||||
document.getElementById("MadhabText").innerText = window.api.getLanguage(lang, "madhab");
|
||||
document.getElementById("Shafi").innerText = window.api.getLanguage(lang, "shafi");
|
||||
document.getElementById("Hanafi").innerText = window.api.getLanguage(lang, "hanafi");
|
||||
document.getElementById("hlrText").innerText = window.api.getLanguage(lang, "hlr");
|
||||
document.getElementById("MOTN").innerText = window.api.getLanguage(lang, "motn");
|
||||
document.getElementById("SOTN").innerText = window.api.getLanguage(lang, "sotn");
|
||||
document.getElementById("TA").innerText = window.api.getLanguage(lang, "ta");
|
||||
document.getElementById("pcrText").innerText = window.api.getLanguage(lang, "pcr");
|
||||
document.getElementById("CC").innerText = window.api.getLanguage(lang, "cc");
|
||||
document.getElementById("CD").innerText = window.api.getLanguage(lang, "cd");
|
||||
document.getElementById("UND").innerText = window.api.getLanguage(lang, "und");
|
||||
document.getElementById("ShafaqText").innerText = window.api.getLanguage(lang, "shafaq");
|
||||
document.getElementById("shafaqG").innerText = window.api.getLanguage(lang, "general");
|
||||
document.getElementById("shafaqR").innerText = window.api.getLanguage(lang, "ahmer");
|
||||
document.getElementById("shafaqW").innerText = window.api.getLanguage(lang, "abyad");
|
||||
document.getElementById("autoStartText").innerText = window.api.getLanguage(lang, "autoStart");
|
||||
document.getElementById("autoStartCheckText").innerText = window.api.getLanguage(lang, "startAtLaunch");
|
||||
document.getElementById("quote").innerText = window.api.getLanguage(lang, "quote");
|
||||
document.getElementById("source").innerText = window.api.getLanguage(lang, "source");
|
||||
document.getElementById("startUpSoundText").innerText = window.api.getLanguage(lang, "startUpSound");
|
||||
document.getElementById("startUpSoundText2").innerText = window.api.getLanguage(lang, "playSound");
|
||||
document.getElementById("systrayText").innerText = window.api.getLanguage(lang, "sysTray");
|
||||
document.getElementById("systrayCheckText").innerText = window.api.getLanguage(lang, "minToTray");
|
||||
document.getElementById("customSettText").innerText = window.api.getLanguage(lang, "customSettings");
|
||||
document.getElementById("enableCalcText").innerText = window.api.getLanguage(lang, "enableCS");
|
||||
document.getElementById("fajrAngleText").innerText = window.api.getLanguage(lang, "fAngle");
|
||||
document.getElementById("maghribAngleText").innerText = window.api.getLanguage(lang, "mAngle");
|
||||
document.getElementById("ishaAngleText").innerText = window.api.getLanguage(lang, "iAngle");
|
||||
document.getElementById("delayText").innerText = window.api.getLanguage(lang, "delayAfterM");
|
||||
document.getElementById("delayFormText").innerText = window.api.getLanguage(lang, "delayMin");
|
||||
|
||||
document.getElementById("France12").innerText = window.api.getLanguage(lang, "france") + " 12";
|
||||
document.getElementById("France15").innerText = window.api.getLanguage(lang, "france") + " 15";
|
||||
document.getElementById("France18").innerText = window.api.getLanguage(lang, "france") + " 18";
|
||||
document.getElementById("Russia").innerText = window.api.getLanguage(lang, "russia");
|
||||
document.getElementById("Gulf").innerText = window.api.getLanguage(lang, "gulf");
|
||||
document.getElementById("adjustmentsText").innerHTML = window.api.getLanguage(lang, "adjustements");
|
||||
document.getElementById("adjCheckText").innerText = window.api.getLanguage(lang, "enableAdj");
|
||||
document.getElementById("fajrAdjText").innerText = window.api.getLanguage(lang, "fajrAdj");
|
||||
document.getElementById("dhuhrAdjText").innerText = window.api.getLanguage(lang, "dhuhrAdj");
|
||||
document.getElementById("asrAdjText").innerText = window.api.getLanguage(lang, "asrAdj");
|
||||
document.getElementById("maghribAdjText").innerText = window.api.getLanguage(lang, "maghribAdj");
|
||||
document.getElementById("ishaAdjText").innerText = window.api.getLanguage(lang, "ishaAdj");
|
||||
document.getElementById("sunnahTimesText").innerText = window.api.getLanguage(lang, "showSunnah");
|
||||
document.getElementById("MOTNCheckText").innerText = window.api.getLanguage(lang, "motn");
|
||||
document.getElementById("TOTNCheckText").innerText = window.api.getLanguage(lang, "totn");
|
||||
document.getElementById("minStartCheckText").innerText = window.api.getLanguage(lang, "minStart");
|
||||
document.getElementById("adhanMecca").innerHTML = window.api.getLanguage(lang, "AdhanMecca");
|
||||
document.getElementById("adhanAqsa").innerHTML = window.api.getLanguage(lang, "adhanAqsa");
|
||||
|
||||
document.getElementById("quranFontText").innerHTML = window.api.getLanguage(lang, "font");
|
||||
document.getElementById("quranFontSizeText").innerHTML = window.api.getLanguage(lang, "fontsize");
|
||||
document.getElementById("translationText").innerHTML = window.api.getLanguage(lang, "translation");
|
||||
document.getElementById("showTranslationCheckText").innerHTML = window.api.getLanguage(lang, "showTrans");
|
||||
document.getElementById("quranLangCheckText").innerHTML = window.api.getLanguage(lang, "diffLang");
|
||||
document.getElementById("translationFontSizeText").innerHTML = window.api.getLanguage(lang, "fontsize");
|
||||
document.getElementById("transliterationText").innerHTML = window.api.getLanguage(lang, "transliteration");
|
||||
document.getElementById("showTransliterationCheckText").innerHTML = window.api.getLanguage(lang, "showTransliteration");
|
||||
document.getElementById("transliterationFontSizeText").innerHTML = window.api.getLanguage(lang, "fontsize");
|
||||
}
|
||||
|
||||
|
||||
async function loadCustomSettings(){
|
||||
var customValues = await window.api.getFromStore('customSettings', [false, 0,0,0]);
|
||||
var customCheck = document.getElementById('customCalcCheck');
|
||||
var fajrAngle = document.getElementById("fajrAngle");
|
||||
var maghribAngle = document.getElementById("maghribAngle");
|
||||
var ishaAngle = document.getElementById("ishaAngle");
|
||||
|
||||
var delay = await window.api.getFromStore('delay', [false, 0]);
|
||||
var delayCheck = document.getElementById('delayCheck');
|
||||
var delayForm = document.getElementById('delayForm');
|
||||
|
||||
if(customValues[0]){
|
||||
customCheck.checked = true;
|
||||
fajrAngle.value = customValues[1]
|
||||
maghribAngle.value = customValues[2]
|
||||
ishaAngle.value = customValues[3]
|
||||
}
|
||||
else{
|
||||
fajrAngle.disabled = true
|
||||
maghribAngle.disabled = true
|
||||
ishaAngle.disabled = true
|
||||
document.getElementById("calcMethodList").disabled = false;
|
||||
}
|
||||
|
||||
customCheck.addEventListener('change', function(){
|
||||
if (customCheck.checked){
|
||||
fajrAngle.disabled = false
|
||||
maghribAngle.disabled = false
|
||||
ishaAngle.disabled = false
|
||||
document.getElementById("calcMethodList").disabled = true;
|
||||
}
|
||||
else{
|
||||
fajrAngle.disabled = true
|
||||
maghribAngle.disabled = true
|
||||
ishaAngle.disabled = true
|
||||
document.getElementById("calcMethodList").disabled = false;
|
||||
}
|
||||
})
|
||||
|
||||
if (delay[0]){
|
||||
delayCheck.checked = true
|
||||
delayForm.value = delay[1]
|
||||
}else{
|
||||
delayForm.disabled = true;
|
||||
}
|
||||
|
||||
delayCheck.addEventListener("change", function(){
|
||||
if(delayCheck.checked){
|
||||
delayForm.disabled = false;
|
||||
}
|
||||
else{
|
||||
delayForm.disabled = true;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function saveCustomSettings(){
|
||||
var customCheck = document.getElementById('customCalcCheck');
|
||||
var delayCheck = document.getElementById('delayCheck');
|
||||
if(customCheck.checked){
|
||||
var fajrAngle = document.getElementById("fajrAngle");
|
||||
var maghribAngle = document.getElementById("maghribAngle");
|
||||
var ishaAngle = document.getElementById("ishaAngle");
|
||||
await window.api.setToStore('customSettings', [true, fajrAngle.value, maghribAngle.value, ishaAngle.value])
|
||||
}
|
||||
else{
|
||||
await window.api.setToStore('customSettings', [false, 0,0,0])
|
||||
}
|
||||
|
||||
if(delayCheck.checked){
|
||||
var delayForm = document.getElementById('delayForm');
|
||||
await window.api.setToStore('delay', [true, delayForm.value])
|
||||
}
|
||||
else{
|
||||
await window.api.setToStore('delay', [false, 0])
|
||||
}
|
||||
}
|
||||
|
||||
//Loads the prayer times adjustements from the store and adds an event listener for the adjustements check box
|
||||
async function loadAdjustments(){
|
||||
var adjustements = await window.api.getFromStore('adj', [false, 0,0,0,0,0]);
|
||||
for (let i = 1; i <= 5; i++){
|
||||
if (adjustements[i] == undefined){
|
||||
adjustements[i] = 0;
|
||||
}
|
||||
}
|
||||
document.getElementById("adjCheck").checked = adjustements[0];
|
||||
document.getElementById("fajrAdjInput").value = adjustements[1];
|
||||
document.getElementById("dhuhrAdjInput").value = adjustements[2];
|
||||
document.getElementById("asrAdjInput").value = adjustements[3];
|
||||
document.getElementById("maghribAdjInput").value = adjustements[4];
|
||||
document.getElementById("ishaAdjInput").value = adjustements[5];
|
||||
|
||||
enableAdjustements(document.getElementById("adjCheck").checked)
|
||||
|
||||
document.getElementById("adjCheck").addEventListener("change", function(){
|
||||
enableAdjustements(document.getElementById("adjCheck").checked)
|
||||
})
|
||||
|
||||
function enableAdjustements(boolean){
|
||||
document.getElementById("fajrAdjInput").disabled = !boolean;
|
||||
document.getElementById("dhuhrAdjInput").disabled = !boolean;
|
||||
document.getElementById("asrAdjInput").disabled = !boolean;
|
||||
document.getElementById("maghribAdjInput").disabled = !boolean;
|
||||
document.getElementById("ishaAdjInput").disabled = !boolean;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Rounds the adjustements (Math.round) and saves them to the store
|
||||
async function saveAdjustments(){
|
||||
var adjCheck = document.getElementById("adjCheck").checked;
|
||||
var fajrAdj = document.getElementById("fajrAdjInput").value;
|
||||
var dhuhrAdj = document.getElementById("dhuhrAdjInput").value;
|
||||
var asrAdj = document.getElementById("asrAdjInput").value;
|
||||
var maghribrAdj = document.getElementById("maghribAdjInput").value;
|
||||
var ishaAdj = document.getElementById("ishaAdjInput").value;
|
||||
|
||||
var adjustements = [adjCheck, Math.round(fajrAdj),Math.round(dhuhrAdj),Math.round(asrAdj),Math.round(maghribrAdj),Math.round(ishaAdj)]
|
||||
|
||||
await window.api.setToStore('adj', adjustements);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads all elements related to the Quran reader
|
||||
*/
|
||||
async function loadQuranSettings(){
|
||||
let quranFontsize = document.getElementById("quranFontSize")
|
||||
let showTranslationDiv = document.getElementById("showTranslationCheck")
|
||||
let diffLangDiv = document.getElementById("quranLangCheck")
|
||||
let quranLangListDiv = document.getElementById("quranLangList")
|
||||
let transListDiv = document.getElementById("translationList")
|
||||
let transFontSizeDiv = document.getElementById("translationFontSize")
|
||||
let showTransliterationDiv = document.getElementById("showTransliterationCheck")
|
||||
let transliFontSizeDiv = document.getElementById("transliterationFontSize")
|
||||
|
||||
let quran = await window.api.getFromStore('quran', {
|
||||
fontsize: 42,
|
||||
translation:{
|
||||
show: true,
|
||||
lang: {
|
||||
enabled: false,
|
||||
lang: "en"
|
||||
},
|
||||
trans: 131,
|
||||
fontsize: 14
|
||||
},
|
||||
transliteration:{
|
||||
show: true,
|
||||
fontsize: 14
|
||||
},
|
||||
})
|
||||
|
||||
loadTranslationList()
|
||||
loadLanguageList()
|
||||
|
||||
quranFontsize.value = quran.fontsize;
|
||||
showTranslationDiv.checked = quran.translation.show;
|
||||
diffLangDiv.checked = quran.translation.lang.enabled;
|
||||
transFontSizeDiv.value = quran.translation.fontsize;
|
||||
showTransliterationDiv.checked = quran.transliteration.show;
|
||||
transliFontSizeDiv.value = quran.transliteration.fontsize;
|
||||
|
||||
quranDisableListeners()
|
||||
|
||||
|
||||
/**
|
||||
* Loads the list of languages from a downloaded JSON and fill an inputList
|
||||
*/
|
||||
function loadLanguageList(){
|
||||
fetch('../../ressources/quran/languages.json')
|
||||
.then(reponse => reponse.json())
|
||||
.then(json => {
|
||||
for (transLang of json["languages"]){
|
||||
var option = document.createElement("option")
|
||||
option.dataset.language_name = (transLang["translated_name"]["name"]).toLowerCase()
|
||||
option.value = transLang["iso_code"]
|
||||
option.innerText = transLang["native_name"] != "" ? transLang["native_name"] : transLang["name"]
|
||||
|
||||
quranLangListDiv.appendChild(option)
|
||||
}
|
||||
loadDefaultLang()
|
||||
})
|
||||
quranLangListDiv.addEventListener("change", function(){
|
||||
hideTranslations()
|
||||
})
|
||||
diffLangDiv.addEventListener("change", function(){
|
||||
if (!diffLangDiv.checked){
|
||||
loadDefaultLang()
|
||||
}
|
||||
})
|
||||
document.getElementById("langlist").addEventListener("change",function(){
|
||||
if (!diffLangDiv.checked){
|
||||
console.log("YES")
|
||||
loadDefaultLang()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when "Different languages from app" is disabled, it loads the default value (selected general) and changes it and the translation list
|
||||
*/
|
||||
function loadDefaultLang(language = undefined){
|
||||
if (language != undefined){
|
||||
if ((language.value == quran.translation.lang.lang && diffLangDiv.checked) ||
|
||||
(!diffLangDiv.checked && language.value == document.getElementById("langlist").options[document.getElementById("langlist").selectedIndex].value))
|
||||
language.selected = true;
|
||||
hideTranslations()
|
||||
}
|
||||
else{
|
||||
for (let language of quranLangListDiv){
|
||||
if ((language.value == quran.translation.lang.lang && diffLangDiv.checked) ||
|
||||
(!diffLangDiv.checked && language.value == document.getElementById("langlist").options[document.getElementById("langlist").selectedIndex].value))
|
||||
language.selected = true;
|
||||
hideTranslations()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the list of translation from a downloaded JSON and fill an inputList
|
||||
*/
|
||||
function loadTranslationList(){
|
||||
fetch('../../ressources/quran/translations.json')
|
||||
.then(reponse => reponse.json())
|
||||
.then(json => {
|
||||
for (translation of json["translations"]){
|
||||
var option = document.createElement("option")
|
||||
option.dataset.lang = translation["language_name"]
|
||||
option.value = translation["id"]
|
||||
option.innerText = translation["name"]
|
||||
if (option.value == quran.translation.trans) option.selected = true;
|
||||
transListDiv.appendChild(option)
|
||||
}
|
||||
})
|
||||
transListDiv.addEventListener("change", function(){
|
||||
quran.translation.trans = transListDiv.options[transListDiv.selectedIndex].value;
|
||||
console.log(quran.translation.trans)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds listeners to disable some inputs
|
||||
*/
|
||||
function quranDisableListeners(){
|
||||
showTranslationDiv.addEventListener("change", function(){
|
||||
diffLangDiv.disabled = !showTranslationDiv.checked;
|
||||
quranLangListDiv.disabled = !showTranslationDiv.checked || !diffLangDiv.checked;
|
||||
transListDiv.disabled = !showTranslationDiv.checked;
|
||||
transFontSizeDiv.disabled = !showTranslationDiv.checked;
|
||||
})
|
||||
diffLangDiv.addEventListener("change", function(){
|
||||
quranLangListDiv.disabled = !diffLangDiv.checked
|
||||
})
|
||||
diffLangDiv.disabled = !showTranslationDiv.checked;
|
||||
quranLangListDiv.disabled = !showTranslationDiv.checked || !diffLangDiv.checked;
|
||||
transListDiv.disabled = !showTranslationDiv.checked;
|
||||
transFontSizeDiv.disabled = !showTranslationDiv.checked;
|
||||
|
||||
showTransliterationDiv.addEventListener("change", function(){
|
||||
transliFontSizeDiv.disabled = !showTransliterationDiv.checked
|
||||
})
|
||||
transliFontSizeDiv.disabled = !showTransliterationDiv.checked
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the selected language and hides translations that are not in that language
|
||||
*/
|
||||
function hideTranslations(){
|
||||
var selectedOne = false;
|
||||
let selectedLang = quranLangListDiv.options[quranLangListDiv.selectedIndex].dataset.language_name
|
||||
for (translation of transListDiv){
|
||||
translation.dataset.lang == selectedLang ? translation.style.display = "block" : translation.style.display = "none"
|
||||
if ((translation.value == quran.translation.trans || !selectedOne) && translation.style.display == "block"){
|
||||
translation.selected = true;
|
||||
selectedOne = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function saveQuran(){
|
||||
let quran = {
|
||||
fontsize: document.getElementById("quranFontSize").value,
|
||||
translation:{
|
||||
show: document.getElementById("showTranslationCheck").checked,
|
||||
lang: {
|
||||
enabled: document.getElementById("quranLangCheck").checked,
|
||||
lang: document.getElementById("quranLangList").options[document.getElementById("quranLangList").selectedIndex].value
|
||||
},
|
||||
trans: document.getElementById("translationList").options[document.getElementById("translationList").selectedIndex].value,
|
||||
fontsize: document.getElementById("translationFontSize").value
|
||||
},
|
||||
transliteration:{
|
||||
show: document.getElementById("showTransliterationCheck").checked,
|
||||
fontsize: document.getElementById("transliterationFontSize").value
|
||||
},
|
||||
}
|
||||
await window.api.setToStore("quran", quran)
|
||||
}
|
||||
|
||||
function loadQueryString(){
|
||||
const queryString = window.location.search;
|
||||
if (queryString == "?page=quran"){
|
||||
var quranTab = new bootstrap.Tab(document.getElementById("v-pills-quran-tab"))
|
||||
quranTab.show();
|
||||
fromQuran = true;
|
||||
}
|
||||
}
|
||||