├── .gitignore
├── AppImageBuilder.yml
├── LICENSE
├── README.md
├── appimage-appdir.sh
├── appimage-build-fix.sh
├── appimage-build.sh
├── audio
├── Fajr
│ ├── Azzam Douik Takbir.ogg
│ ├── Azzam Douik.ogg
│ ├── Mishary Al-Afasy.ogg
│ ├── Muhammad Muhsen.ogg
│ └── Nasir Al-Qatami Takbir.ogg
└── Normal
│ ├── Abdul Basit.ogg
│ ├── Abdur Ra'uf.ogg
│ ├── Al-Minshawi.ogg
│ ├── Azzam Douik Takbir.ogg
│ ├── Essam Al-Khan.ogg
│ ├── Mishary Al-Afasy.ogg
│ ├── Nasir Al-Qatami Takbir.ogg
│ ├── Nasir Al-Qatami.ogg
│ └── Yusuf Islam.ogg
├── data
└── Locations.xml
├── hijra.py
├── hijrical.py
├── home.py
├── icons
├── arrows
│ ├── arrow-left.svg
│ └── arrow-right.svg
├── hicolor
│ ├── 128x128
│ │ └── apps
│ │ │ ├── silaty.png
│ │ │ └── silaty.svg
│ ├── 24x24
│ │ └── apps
│ │ │ └── silaty.svg
│ ├── 48x48
│ │ └── apps
│ │ │ └── silaty.svg
│ └── scalable
│ │ └── silaty-indicator.svg
└── sidebar
│ ├── aboutA.svg
│ ├── aboutN.svg
│ ├── calendarA.svg
│ ├── calendarN.svg
│ ├── homeA.svg
│ ├── homeN.svg
│ ├── notifyA.svg
│ ├── notifyN.svg
│ ├── qiblaA.svg
│ ├── qiblaN.svg
│ ├── settingsA.svg
│ └── settingsN.svg
├── install.sh
├── lang
├── ar.json
├── en.json
├── es.json
└── fr.json
├── location.py
├── options.py
├── prayertime.py
├── qiblacompass.py
├── screenshots
├── Silaty.png
├── Silaty_calendar.png
├── Silaty_notification.png
├── Silaty_qibla.png
├── Silaty_settings.png
├── linux-download.png
└── windows-download.png
├── settingspane.py
├── sidebar.py
├── silaty-indicator.py
├── silaty.desktop
├── silaty.py
├── silatycal.py
├── snap
└── snapcraft.yaml
├── translate.py
└── uninstall.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | # Custom
2 | *.*~
3 | AppDir/*
4 | appimage-builder-cache/*
5 | *.AppImage
6 |
7 | # Python cache
8 | __pycache__/
9 | *.pyc
10 |
--------------------------------------------------------------------------------
/AppImageBuilder.yml:
--------------------------------------------------------------------------------
1 | # appimage-builder recipe see https://appimage-builder.readthedocs.io for details
2 | version: 1
3 | AppDir:
4 | path: ./AppDir
5 | app_info:
6 | id: com.github.AXeL-dev.silaty
7 | name: Silaty
8 | icon: silaty
9 | version: '1.4'
10 | exec: /usr/local/bin/silaty-indicator
11 | exec_args: $@
12 | runtime:
13 | env:
14 | APPDIR_LIBRARY_PATH: $APPDIR/usr/lib/x86_64-linux-gnu/gvfs:$APPDIR/usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders:$APPDIR/usr/lib/python3.6/lib-dynload:$APPDIR/usr/lib/x86_64-linux-gnu:$APPDIR/usr/lib/x86_64-linux-gnu/gtk-3.0/3.0.0/immodules:$APPDIR/usr/lib/python3/dist-packages/gi:$APPDIR/usr/lib/x86_64-linux-gnu/gio/modules:$APPDIR/usr/lib/x86_64-linux-gnu/gtk-3.0/modules:$APPDIR/lib/x86_64-linux-gnu
15 | apt:
16 | arch: amd64
17 | allow_unauthenticated: true
18 | sources:
19 | - sourceline: deb http://fr.archive.ubuntu.com/ubuntu/ bionic main restricted
20 | - sourceline: deb http://fr.archive.ubuntu.com/ubuntu/ bionic-updates main restricted
21 | - sourceline: deb http://fr.archive.ubuntu.com/ubuntu/ bionic universe
22 | - sourceline: deb http://fr.archive.ubuntu.com/ubuntu/ bionic-updates universe
23 | - sourceline: deb http://fr.archive.ubuntu.com/ubuntu/ bionic multiverse
24 | - sourceline: deb http://fr.archive.ubuntu.com/ubuntu/ bionic-updates multiverse
25 | - sourceline: deb http://fr.archive.ubuntu.com/ubuntu/ bionic-backports main restricted
26 | universe multiverse
27 | - sourceline: deb http://security.ubuntu.com/ubuntu bionic-security main restricted
28 | - sourceline: deb http://security.ubuntu.com/ubuntu bionic-security universe
29 | - sourceline: deb http://security.ubuntu.com/ubuntu bionic-security multiverse
30 | - sourceline: deb http://ppa.launchpad.net/lubomir-brindza/nautilus-typeahead/ubuntu
31 | bionic main
32 | - sourceline: deb http://ppa.launchpad.net/ubuntubudgie/backports/ubuntu bionic
33 | main
34 | - sourceline: deb [arch=amd64] http://packages.microsoft.com/repos/edge/ stable
35 | main
36 | - sourceline: deb [arch=amd64] https://repo.skype.com/deb stable main
37 | - sourceline: deb http://ppa.launchpad.net/bluetooth/bluez/ubuntu bionic main
38 | include:
39 | - appmenu-gtk3-module
40 | - dconf-gsettings-backend
41 | - gvfs
42 | - ibus-gtk3
43 | - libappindicator3-1
44 | - libbz2-1.0
45 | - libcanberra-gtk3-module
46 | - libgcrypt20
47 | - libgstreamer1.0-0
48 | - liblz4-1
49 | - libpcre3
50 | - libpython3.6-stdlib
51 | - librsvg2-common
52 | - libsystemd0
53 | - libxau6
54 | - libxdmcp6
55 | - libxext6
56 | - libxfixes3
57 | - libxinerama1
58 | - libxrender1
59 | - python3-gi
60 | exclude: []
61 | files:
62 | exclude:
63 | - usr/share/man
64 | - usr/share/doc/*/README.*
65 | - usr/share/doc/*/changelog.*
66 | - usr/share/doc/*/NEWS.*
67 | - usr/share/doc/*/TODO.*
68 | test:
69 | fedora:
70 | image: appimagecrafters/tests-env:fedora-30
71 | command: ./AppRun
72 | use_host_x: true
73 | debian:
74 | image: appimagecrafters/tests-env:debian-stable
75 | command: ./AppRun
76 | use_host_x: true
77 | arch:
78 | image: appimagecrafters/tests-env:archlinux-latest
79 | command: ./AppRun
80 | use_host_x: true
81 | centos:
82 | image: appimagecrafters/tests-env:centos-7
83 | command: ./AppRun
84 | use_host_x: true
85 | ubuntu:
86 | image: appimagecrafters/tests-env:ubuntu-xenial
87 | command: ./AppRun
88 | use_host_x: true
89 | AppImage:
90 | arch: x86_64
91 | update-information: guess
92 | sign-key: None
93 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Silaty
2 |
3 | A neat prayer reminder app in GTK
4 |
5 | 
6 |
7 | ## Installation
8 |
9 | [](https://snapcraft.io/silaty)
10 | [](https://snapcraft.io/silaty)
11 | [
](https://github.com/LinuxForGeeks/Silaty/releases/download/v1.4/Silaty-1.4-x86_64.AppImage)
12 | [
](https://github.com/MustafaKhalaf69/SilatyCrossPlatform/releases/download/1.4-updated/SilatyWindows.zip)
13 |
14 | [How to install on windows?](https://github.com/LinuxForGeeks/Silaty/tree/platform/win#windows-configuration)
15 |
16 |
29 |
30 | ### Install from source
31 |
32 | Download or clone this repository with git:
33 |
34 | ```bash
35 | git clone https://github.com/AXeL-dev/Silaty.git
36 | ```
37 |
38 | Make sure that you have all the dependencies installed using the following command:
39 |
40 |
41 | Ubuntu / Debian
42 |
43 | ```bash
44 | sudo apt install gir1.2-gtk-3.0 gir1.2-appindicator3-0.1 gir1.2-notify-0.7 gir1.2-gstreamer-1.0
45 | ```
46 |
47 |
48 |
49 |
50 | Arch Linux
51 |
52 | ```bash
53 | pacman -Syu gtk3 libappindicator-gtk3 libnotify gstreamer
54 | ```
55 |
56 |
57 |
58 | **Note:** this command may change depending on your linux distribution.
59 |
60 | To install run:
61 |
62 | ```bash
63 | cd /path/to/silaty
64 | sudo ./install.sh
65 | ```
66 |
67 | Once installed, you can run Silaty from your applications menu, or using the command bellow:
68 |
69 | ```bash
70 | silaty-indicator
71 | ```
72 |
73 | To uninstall run:
74 |
75 | ```bash
76 | sudo ./uninstall.sh
77 | ```
78 |
79 | ## Changelog
80 |
81 | ### v1.5
82 |
83 | - added [windows support](https://github.com/LinuxForGeeks/Silaty/tree/platform/win), thanks to [@MustafaKhalaf69](https://github.com/MustafaKhalaf69).
84 | - added short takbir audios.
85 | - fixed notify package version on arch linux.
86 | - enhanced translation mechanism.
87 | - added french & spanish translations, thanks to [@DBChoco](https://github.com/DBChoco).
88 | - fixed prayer times alignment.
89 |
90 | ### v1.4
91 |
92 | - added snap & appimage packages.
93 | - fixed prayer times issues on some locations.
94 |
95 | ### v1.3
96 |
97 | - arabic language is now supported.
98 | - app crash on KDE desktop fixed.
99 |
100 | ### v1.2
101 |
102 | - [Silaty unable to sync prayer times correctly !! #9](https://github.com/Jessewb786/Silaty/issues/9) fixed.
103 | - [Hijri Date #8](https://github.com/Jessewb786/Silaty/issues/8) fixed.
104 | - update home title when stack changes.
105 |
106 | ### v1.1
107 |
108 | - LICENSE added.
109 | - [Add screenshots #3](https://github.com/Jessewb786/Silaty/issues/3).
110 | - README updated.
111 | - attempt to clean code.
112 | - GTK warnings fixed.
113 | - switching between sidebar tabs from indicator menu fixed.
114 | - about tab added/implemented into sidebar.
115 | - fixed a crash when closing the main window.
116 | - [Settings won't open #2](https://github.com/Jessewb786/Silaty/issues/2) fixed.
117 | - load notification icon from its path instead of using an icon name.
118 | - use default layout size, instead of using a fixed window size.
119 | - refresh prayer times on home tab when changing settings.
120 | - useless debug messages commented (especially those used in main loop).
121 | - attempt to fix [installing error #4](https://github.com/Jessewb786/Silaty/issues/4) by ignoring pycompile cmd.
122 | - timezone added to location settings.
123 | - get location using Google Maps API disabled (no longer works).
124 | - daylight saving time setting added.
125 | - display/hide main window from indicator menu fixed.
126 | - location search button added.
127 | - wrong time suffix (AM/PM) when using 12h clock format fixed.
128 | - solve some class naming conflicts.
129 | - [Locations.xml](data/Locations.xml) updated from [libgweather](https://github.com/GNOME/libgweather) repository.
130 | - grabbing timezone from locations xml file done.
131 | - remaining time until next prayer corrected.
132 |
133 | ### v1.0
134 |
135 | - first release
136 |
137 | ## ToDo
138 |
139 | - [x] fix settings issues (especially Location settings).
140 | - [x] use a custom list to get/set location (@see [Minbar](https://github.com/fajran/minbar)).
141 | - [x] remove duplicate locations/cities in [Locations.xml](data/Locations.xml).
142 | - [ ] translate to other languages.
143 | - [ ] support dark mode.
144 |
145 | ## Credits
146 |
147 | - [Jessewb786](https://github.com/Jessewb786)
148 |
149 | ## License
150 |
151 | Silaty is licensed under the [GPL license](LICENSE).
152 |
--------------------------------------------------------------------------------
/appimage-appdir.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | mkdir -p AppDir/usr/share/silaty
4 | mkdir -p AppDir/usr/share/icons/hicolor/scalable/apps/
5 | mkdir -p AppDir/usr/share/icons/hicolor/128x128/apps/
6 | mkdir -p AppDir/usr/share/icons/hicolor/48x48/apps/
7 | mkdir -p AppDir/usr/share/icons/hicolor/24x24/apps/
8 | mkdir -p AppDir/usr/share/applications
9 | mkdir -p AppDir/etc/xdg/autostart
10 | mkdir -p AppDir/usr/local/bin
11 | cp -R icons AppDir/usr/share/silaty/
12 | cp -R audio AppDir/usr/share/silaty/
13 | cp -R data AppDir/usr/share/silaty/
14 |
15 | cp icons/hicolor/128x128/apps/silaty.svg AppDir/usr/share/icons/hicolor/scalable/apps/
16 | cp icons/hicolor/128x128/apps/silaty.png AppDir/usr/share/icons/hicolor/scalable/apps/
17 | cp icons/hicolor/128x128/apps/silaty.svg AppDir/usr/share/icons/
18 | cp icons/hicolor/128x128/apps/silaty.png AppDir/usr/share/icons/
19 | chmod 644 AppDir/usr/share/icons/hicolor/scalable/apps/silaty.svg
20 |
21 | cp icons/hicolor/128x128/apps/silaty.svg AppDir/usr/share/icons/hicolor/128x128/apps/
22 | chmod 644 AppDir/usr/share/icons/hicolor/128x128/apps/silaty.svg
23 |
24 | cp icons/hicolor/48x48/apps/silaty.svg AppDir/usr/share/icons/hicolor/48x48/apps/
25 | chmod 644 AppDir/usr/share/icons/hicolor/48x48/apps/silaty.svg
26 |
27 | cp icons/hicolor/24x24/apps/silaty.svg AppDir/usr/share/icons/hicolor/24x24/apps/
28 | chmod 644 AppDir/usr/share/icons/hicolor/24x24/apps/silaty.svg
29 |
30 | cp *.py AppDir/usr/share/silaty/
31 | chmod 755 -R AppDir/usr/share/silaty/
32 |
33 | cp silaty.desktop AppDir/etc/xdg/autostart/
34 | chmod 755 AppDir/etc/xdg/autostart/silaty.desktop
35 |
36 | cp silaty.desktop AppDir/usr/share/applications/
37 | chmod 755 AppDir/usr/share/applications/silaty.desktop
38 |
39 | ln -sf /usr/share/silaty/silaty-indicator.py AppDir/usr/local/bin/silaty-indicator
40 | #chmod 755 AppDir/usr/local/bin/silaty-indicator
41 |
--------------------------------------------------------------------------------
/appimage-build-fix.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ "$(id -u)" != "0" ]; then
4 | echo “This script must be run as root” 2>&1
5 | exit 1
6 | fi
7 |
8 | sed -i '/raise RuntimeError(.*/i \ return "x86_64"' /usr/local/lib/python3.6/dist-packages/appimagebuilder/common/elf.py
9 |
--------------------------------------------------------------------------------
/appimage-build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | sh appimage-appdir.sh
4 |
5 | appimage-builder --skip-test --skip-appimage
6 |
7 | gdk-pixbuf-query-loaders > AppDir/usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders.cache
8 |
9 | # For test purpose
10 | #AppDir/AppRun
11 |
12 | appimage-builder --skip-test --skip-build
13 |
--------------------------------------------------------------------------------
/audio/Fajr/Azzam Douik Takbir.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/audio/Fajr/Azzam Douik Takbir.ogg
--------------------------------------------------------------------------------
/audio/Fajr/Azzam Douik.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/audio/Fajr/Azzam Douik.ogg
--------------------------------------------------------------------------------
/audio/Fajr/Mishary Al-Afasy.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/audio/Fajr/Mishary Al-Afasy.ogg
--------------------------------------------------------------------------------
/audio/Fajr/Muhammad Muhsen.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/audio/Fajr/Muhammad Muhsen.ogg
--------------------------------------------------------------------------------
/audio/Fajr/Nasir Al-Qatami Takbir.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/audio/Fajr/Nasir Al-Qatami Takbir.ogg
--------------------------------------------------------------------------------
/audio/Normal/Abdul Basit.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/audio/Normal/Abdul Basit.ogg
--------------------------------------------------------------------------------
/audio/Normal/Abdur Ra'uf.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/audio/Normal/Abdur Ra'uf.ogg
--------------------------------------------------------------------------------
/audio/Normal/Al-Minshawi.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/audio/Normal/Al-Minshawi.ogg
--------------------------------------------------------------------------------
/audio/Normal/Azzam Douik Takbir.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/audio/Normal/Azzam Douik Takbir.ogg
--------------------------------------------------------------------------------
/audio/Normal/Essam Al-Khan.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/audio/Normal/Essam Al-Khan.ogg
--------------------------------------------------------------------------------
/audio/Normal/Mishary Al-Afasy.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/audio/Normal/Mishary Al-Afasy.ogg
--------------------------------------------------------------------------------
/audio/Normal/Nasir Al-Qatami Takbir.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/audio/Normal/Nasir Al-Qatami Takbir.ogg
--------------------------------------------------------------------------------
/audio/Normal/Nasir Al-Qatami.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/audio/Normal/Nasir Al-Qatami.ogg
--------------------------------------------------------------------------------
/audio/Normal/Yusuf Islam.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/audio/Normal/Yusuf Islam.ogg
--------------------------------------------------------------------------------
/hijra.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | """
4 | Hijri Islamic Calendar converting functions,
5 | Copyright (c) 2006-2008 Muayyad Saleh Alsadi
6 | Based on an enhanced algorithm designed by me
7 | the algorithm is discussed in a book titled "حتى لا ندخل جحور الضباب"
8 | (not yet published)
9 |
10 | This file can be used to implement apps, gdesklets or karamba ..etc
11 |
12 | This algorithm is based on integer operations
13 | which that there is no round errors (given accurate coefficients)
14 | the accuracy of this algorithm is based on 3 constants (p,q and a)
15 | where p/q is the full months percentage [ gcd(p,q) must be 1 ]
16 | currently it's set to 191/360 which mean that there is 191 months
17 | having 30 days in a span of 360 years, other months are 29 days.
18 | and a is just a shift.
19 |
20 |
21 | Released under terms on Waqf Public License.
22 | This program is free software; you can redistribute it and/or modify
23 | it under the terms of the latest version Waqf Public License as
24 | published by Ojuba.org.
25 |
26 | This program is distributed in the hope that it will be useful,
27 | but WITHOUT ANY WARRANTY; without even the implied warranty of
28 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
29 |
30 | The Latest version of the license can be found on
31 | "http://www.ojuba.org/wiki/doku.php/waqf/license"
32 |
33 |
34 | Portions of this algorithm is based on that found on GNU EMACS
35 | the difference is that this algorithm does not set
36 | all months to a fixed number of days (in the original algorithm
37 | first month always have 30 days)
38 |
39 |
40 | The original GNU Emacs LISP algorithm
41 | Copyright (C) 1995, 1997, 2001 Free Software Foundation, Inc.
42 | Edward M. Reingold
43 | Technical details of all the calendrical calculations can be found in
44 | ``Calendrical Calculations'' by Nachum Dershowitz and Edward M. Reingold,
45 | Cambridge University Press (1997).
46 | Comments, corrections, and improvements should be sent to
47 | Edward M. Reingold Department of Computer Science
48 | (217) 333-6733 University of Illinois at Urbana-Champaign
49 | reingold@cs.uiuc.edu 1304 West Springfield Avenue
50 | """
51 | __p_const=191
52 | __q_const=360
53 | __a_const=48
54 | __hijri_epoch=227015 # = Julian 0622-7-16 = gregorian 0759-6-11 (I think it should be 622, 7, 19)
55 | # TODO: Why does the the hijri_epoch 227015 does not give the expected value when converted to gregorian
56 |
57 | def get_consts():
58 | """Return a tuple of the 3 constants (p,q,a) used by this algothim, for debuging"""
59 | return (__p_const, __q_const, __a_const)
60 |
61 | def get_epoch():
62 | """Return Hijri epoch, number of days since gregorian epoch, (should be Julian 0622-7-16 (ie. 227015 days)"""
63 | return __hijri_epoch
64 |
65 | def hijri_month_days(Y,M):
66 | """Return the number of days in a given hijri month M in a given Y"""
67 | Mc = ( Y -1) *12 + M
68 | if (((Mc+ __a_const) * __p_const) % __q_const) < __p_const : return 30
69 | else: return 29
70 |
71 | # NOTE: trivial implementation
72 | #def hijri_days_before_month_(Y,M): # simple mothod, optimization is possible by reusing Mc ..etc.
73 | # """Return the number of days before a given moth M in a given year Y"""
74 | # sum=0
75 | # for i in range(1,M): sum+=hijri_month_days(Y,i);
76 | # return sum
77 |
78 | def hijri_days_before_month(Y,M):
79 | """Return the number of days before a given moth M in a given year Y (0 for M=1)"""
80 | Mc = (Y -1) *12 + 1 + __a_const
81 | McM=Mc * __p_const
82 | sum=0
83 | for i in range(1,M):
84 | if (McM % __q_const) < __p_const : sum+=30
85 | else: sum+=29
86 | McM+=__p_const
87 | return sum
88 |
89 | #TEST: PASSED
90 | # test that the faster hijri_days_before_month is ok
91 | #def test_hijri_days_before_month():
92 | # l=[(y,m) for y in range(1400,1499) for m in range(1,13)]
93 | # for y,m in l:
94 | # d1=hijri_days_before_month(y,m)
95 | # d2=hijri_days_before_month_(y,m)
96 | # if d1!=d2: print y,m,d1,d2
97 |
98 |
99 | def hijri_year_days(Y):
100 | """Return the number of days in a given year Y"""
101 | return hijri_days_before_month(Y,13)
102 |
103 | def hijri_day_number (Y, M, D):
104 | """Return the day number within the year of the Islamic date (Y, M, D), 1 for 1/1 in any year"""
105 | return hijri_days_before_month(Y,M)+D
106 |
107 |
108 | # BAD fast implementation
109 | #def hijri_to_absolute_ (Y, M, D):
110 | # """Return absolute date of Hijri (Y,M,D), eg. ramadan (9),1,1427 -> 732578 """
111 | # Mc=(Y-1)*12
112 | # # days before Hijra + days in the years before + days from the begining of that year
113 | # return __hijri_epoch + \
114 | # Mc*29 + Mc*__p_const/__q_const + \ # this line should involve __a_const
115 | # hijri_day_number (Y, M, D) - 1
116 |
117 | # correct implementation # TODO: optimize it more and test that after optimization
118 | def hijri_to_absolute (Y, M, D):
119 | """Return absolute date of Hijri (Y,M,D), eg. ramadan (9),1,1427 -> 732578 """
120 | Mc=(Y-1)*12
121 | # day count=days before Hijra plus (...)
122 | dc=__hijri_epoch
123 | # plus days in the years before till first multiples of q plus (...)
124 | Mc-=Mc % __q_const
125 | y=Y-Mc//12
126 | dc+=Mc*29 + Mc*__p_const//__q_const
127 | # plus those after the multiples plus (...)
128 | for i in range(1,y): dc += hijri_year_days(i)
129 | # plus days from the begining of that year
130 | dc+=hijri_day_number (Y, M, D) - 1
131 | return dc
132 |
133 | def hijri_month_days_(y,m):
134 | """Return the number of days in a given hijri month M in a given Y"""
135 | return hijri_to_absolute(y+m//12,m%12+1,1)-hijri_to_absolute(y,m,1)
136 |
137 | # TEST: PASSED
138 | #def test_hijri_to_absolute_v_month_days():
139 | # #l=[(y,m) for y in range(1,31) for m in range(1,13)]
140 | # l=[(y,m) for y in range(1400,1499) for m in range(1,13)]
141 | # for y,m in l:
142 | # d1=hijri_month_days(y,m)
143 | # d2=hijri_to_absolute(y+m/12,m%12+1,1)-hijri_to_absolute(y,m,1)
144 | # if d1!=d2: print y,m,y+m/12,m%12+1,'d1=',d1,", d2=",d2
145 |
146 | # round then move to exact, very slow perfect implementation
147 | #def absolute_to_hijri_ (date): # TODO: check if it's always compatible with absolute_from_hijri
148 | # """Return Hijri date (Y,M,D) corresponding to the given absolute number of days."""
149 | # if date < __hijri_epoch: return None; # pre-Islamic date
150 | # dd=date-__hijri_epoch
151 | # Mc=dd/(29*(__q_const-__p_const)+ 30*__p_const)*__q_const # mounth count till multibles of q
152 | # Y=y=Mc/12+1; M=m=(Mc%12)+1
153 | # while(date > hijri_to_absolute(Y,M,1)):
154 | # y,m=Y,M
155 | # M+=1
156 | # if M>12: M=1; Y+=1
157 | # Y=y; M=m
158 | # D=1 + date - hijri_to_absolute(Y,M,1)
159 | # if D>hijri_month_days(Y,M):
160 | # M+=1
161 | # if M>12: M=1; Y+=1
162 | # D=1 + date - hijri_to_absolute(Y,M,1)
163 | # return (Y,M,D)
164 |
165 |
166 | # direct way, test PASSED
167 | def absolute_to_hijri (date):
168 | """Return Hijri date (Y,M,D) corresponding to the given absolute number of days."""
169 | if date < __hijri_epoch: return None; # pre-Islamic date
170 | Mc=(date-__hijri_epoch+1)*__q_const//(29*__q_const+__p_const)
171 | Y=Mc//12+1; M=(Mc%12)+1
172 | # consistency check
173 | d=hijri_to_absolute(Y,M,1) # TODO: this is an expensive call
174 | if (date < d): # go one month back if needed
175 | M-=1
176 | if M==0: Y-=1; M=12
177 | d-=hijri_month_days(Y,M) # this call is fast
178 | #
179 | D=1 + date - d
180 | return (Y,M,D)
181 |
182 | # TEST: PASSED
183 | #def test_c():
184 | # l=[(y,m) for y in range(1400,1499) for m in range(1,13)]
185 | # for y,m in l:
186 | # d=hijri_month_days(y,m)
187 | # if absolute_to_hijri(hijri_to_absolute(y,m,1))!=(y,m,1): print y,m,1, absolute_to_hijri(hijri_to_absolute(y,m,1))
188 | # if absolute_to_hijri(hijri_to_absolute(y,m,d))!=(y,m,d): print y,m,d, absolute_to_hijri(hijri_to_absolute(y,m,d))
189 |
190 | def hijri_day_of_week (Y, M, D):
191 | """Return the day-of-the-week index of hijri (Y,M,D) Date, 0 for Sunday, 1 for Monday, etc."""
192 | return hijri_to_absolute (Y,M, D) % 7
193 | # ///////////////////////////////
194 | # high level converting functions
195 |
196 | def hijri_to_gregorian (year, month, day):
197 | """Return gregorian (year, month, day) converted from Islamic Hijri calender"""
198 | return absolute_to_gregorian( hijri_to_absolute (year, month, day))
199 |
200 | def gregorian_to_hijri (year, month, day):
201 | """Return Hijri (year, month, day) converted from gregorian calender"""
202 | return absolute_to_hijri( gregorian_to_absolute (year, month, day))
203 |
204 | #///////////////////////////////////
205 | # Gregorian functions
206 | #///////////////////////////////////
207 | # This Portions of is based on that found on GNU EMACS
208 |
209 | #The original GNU Emacs LISP algorithm
210 | #Copyright (C) 1995, 1997, 2001 Free Software Foundation, Inc.
211 | # Edward M. Reingold
212 | # Technical details of all the calendrical calculations can be found in
213 | # ``Calendrical Calculations'' by Nachum Dershowitz and Edward M. Reingold,
214 | # Cambridge University Press (1997).
215 | # Comments, corrections, and improvements should be sent to
216 | # Edward M. Reingold Department of Computer Science
217 | # (217) 333-6733 University of Illinois at Urbana-Champaign
218 | # reingold@cs.uiuc.edu 1304 West Springfield Avenue
219 |
220 | days_in_month=( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
221 | def gregorian_leap_year_p (year):
222 | """Return 1 (True) if YEAR is a Gregorian leap year."""
223 | if ((year % 4) == 0 and ((year % 100) or (year % 400) == 0)): return 1;
224 | return 0;
225 |
226 | def gregorian_month_days (year, month):
227 | """The last day in MONTH during YEAR."""
228 | if (month == 2 and gregorian_leap_year_p (year)): return 29;
229 | return days_in_month[month-1];
230 |
231 | def gregorian_day_number (year, month, day):
232 | """Return the day number within the year of the date (year,month, day)"""
233 | if month<3: return day + (31 * (month - 1))
234 | return day + (31 * (month - 1)) - \
235 | ((month << 2) + 23) // 10 + (gregorian_leap_year_p (year) & 1);
236 |
237 | def gregorian_to_absolute (year, month, day):
238 | prior_years = year - 1
239 | return gregorian_day_number (year, month, day) + \
240 | (365 * prior_years + (prior_years >> 2)) - \
241 | (prior_years // 100) + (prior_years // 400)
242 |
243 | def absolute_to_gregorian(date):
244 | """return (year month day) corresponding to the absolute DATE.
245 | The absolute date is the number of days elapsed since the (imaginary)
246 | Gregorian date Sunday, December 31, 1 BC."""
247 |
248 | # See the footnote on page 384 of ``Calendrical Calculations, Part II:
249 | # Three Historical Calendars'' by E. M. Reingold, N. Dershowitz, and S. M.
250 | # Clamen, Software--Practice and Experience, Volume 23, Number 4
251 | # (April, 1993), pages 383-404 for an explanation.
252 | d0 = date - 1;
253 | n400 = d0 // 146097;
254 | d1 = d0 % 146097;
255 | n100 = d1 // 36524;
256 | d2 = d1 % 36524;
257 | n4 = d2 // 1461;
258 | d3 = d2 % 1461;
259 | n1 = d3 // 365;
260 | dd = (d3 % 365) + 1;
261 | yy = ((400 * n400) + (100 * n100) + (n4 * 4) + n1);
262 | if (n100 == 4) or (n1 == 4): return (yy, 12, 31);
263 | yy=yy+1;
264 | mm = 1;
265 | while(date >= gregorian_to_absolute (yy,mm, 1)): mm+=1;
266 | d=gregorian_to_absolute (yy, mm-1, 1);
267 | return (yy, mm-1,date-d+1);
268 | # d = calendar_absolute_from_gregorian (1, 1, yy);
269 | # mm=1;
270 | # while(mm <= 12):
271 | # dd = date - d + 1;
272 | # dm = calendar_last_day_of_month (mm, yy);
273 | # if dd <= dm: return (mm,dd+1,yy);
274 | # d += dm;
275 | # mm=mm+1;
276 | # return 0; # should not happened
277 | def gregorian_day_of_week (yy, mm, dd):
278 | """Return the day-of-the-week index of gregorian (yy, mm, dd) DATE, 0 for Sunday, 1 for Monday, etc."""
279 | return gregorian_to_absolute (yy,mm, dd) % 7;
280 | # ///////////////////////////////
281 | # some tests for debuging to be removed
282 |
283 | def test1():
284 | global __a_const;
285 | __a_const=48
286 | for __a_const in range(0,100): unmatched=0; from_y=1; to_y=4001
287 | for y in range(from_y,to_y):
288 | if hijri_days(y)!=emacs_hijri_days(y): unmatched+=1
289 | print ("%d years (%g %%) unmatched when a=%d", (unmatched, float(float(unmatched)/(to_y-from_y)), __a_const))
290 | __a_const=48
291 | sum=0.0
292 | for y in range(1,4001): sum+=hijri_days(y)
293 | print ("year len=%f ", float(float(sum)/4000.0*100.0))
294 | __a_const=47
295 | sum=0.0
296 | for y in range(1,4001): sum+=hijri_days(y)
297 | print ("year len=%f ", float(float(sum)/4000.0*100.0))
298 | ##########################
299 | if __name__ == "__main__":
300 | # conclusion
301 | # 0% for a=16 48 65
302 | # 7% for a=1 31 33 50 80 82 97 99
303 | # 13% for a=14 18 46 63 67 95
304 | # 20% for a=12 29 3 35 52 78 84
305 | # ...
306 | # 73% for a=45 47 49 ..etc.
307 | ##########################
308 | __a_const=16
309 | print ("for a=%d", __a_const)
310 | sum=0.0
311 | for y in range(1,4001): sum+= float(hijri_month_days(y,12)==30)
312 | print ("perfect thu-hijja months is %f %% ", float(float(sum)/4000.0*100.0))
313 | sum=0.0
314 | for y in range(1,4001): sum+= float(hijri_month_days(y,9)==30)
315 | print ("perfect Ramadan months is %f %% ", float(float(sum)/4000.0*100.0))
316 |
317 | __a_const=48
318 | print ("for a=%d", __a_const)
319 | sum=0.0
320 | for y in range(1,4001): sum+= float(hijri_month_days(y,12)==30)
321 | print ("perfect thu-hijja months is %f %% ", float(float(sum)/4000.0*100.0))
322 | sum=0.0
323 | for y in range(1,4001): sum+= float(hijri_month_days(y,9)==30)
324 | print ("perfect Ramadan months is %f %% ", float(float(sum)/4000.0*100.0))
325 |
326 | __a_const=65
327 | print ("for a=%d", __a_const)
328 | sum=0.0
329 | for y in range(1,4001): sum+= float(hijri_month_days(y,12)==30)
330 | print ("perfect thu-hijja months is %f %% ", float(float(sum)/4000.0*100.0))
331 | sum=0.0
332 | for y in range(1,4001): sum+= float(hijri_month_days(y,9)==30)
333 | print ("perfect Ramadan months is %f %% ", float(float(sum)/4000.0*100.0))
334 |
335 | __a_const=48
336 | print ("for a=%d", __a_const)
337 | for m in range(1,13):
338 | sum=0.0
339 | for y in range(1,4001): sum+= float(hijri_month_days(y,m)==30)
340 | print ("perfect %d months is %f %% ", (m,float(float(sum)/4000.0*100.0)))
341 |
--------------------------------------------------------------------------------
/hijrical.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | """
4 | Hijri Islamic High level Calendar API,
5 | Copyright (c) 2006-2008 Muayyad Saleh Alsadi
6 | Based on an enhanced algorithm designed by me
7 | the algorithm is discussed in a book titled "حتى لا ندخل جحور الضباب"
8 | (not yet published)
9 |
10 | This file can be used to implement apps, gdesklets or karamba ..etc
11 |
12 | The algorith itself is not here, it's in another file called hijra.py
13 |
14 | Released under terms on Waqf Public License.
15 | This program is free software; you can redistribute it and/or modify
16 | it under the terms of the latest version Waqf Public License as
17 | published by Ojuba.org.
18 |
19 | This program is distributed in the hope that it will be useful,
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22 |
23 | The Latest version of the license can be found on
24 | "http://www.ojuba.org/wiki/doku.php/waqf/license"
25 |
26 | """
27 | from time import localtime
28 | from hijra import *
29 |
30 | class HijriCal:
31 | """a Class that provide a high level Islamic Hijri calendar API"""
32 | def __init__(self, adjustment=0):
33 | self.adjustment = adjustment
34 | """Create HijriCal Object"""
35 | self.__md = [[""]*7,[""]*7,[""]*7,[""]*7,[""]*7,[""]*7] # 7 days on at most 6 weeks
36 | self.__g_md = [[""]*7,[""]*7,[""]*7,[""]*7,[""]*7,[""]*7] # 7 days on at most 6 weeks
37 | self.__direct =- 1
38 | self.__ws = 6 # make Sat is first day of week, and fill rows directly
39 | self.goto_today()
40 |
41 | def goto_today(self):
42 | """Jump to today"""
43 | yy, mm, dd = localtime()[:3]
44 | self.g_today = (yy, mm, dd)
45 | Y, M, D = self.goto_gregorian_day(yy, mm, dd)
46 | wd = hijri_day_of_week (Y, M, D)
47 | self.today = (Y, M, D, wd)
48 |
49 | def refresh_today(self):
50 | """check is today is uptodate, update them if not and return True"""
51 | if self.g_today==localtime()[:3]:
52 | return False
53 | else:
54 | yy, mm, dd = localtime()[:3]
55 | self.g_today= (yy, mm, dd)
56 | dd += int(self.adjustment) # adjust hijri calendar
57 | Y, M, D = gregorian_to_hijri(yy, mm, dd)
58 | wd = hijri_day_of_week (Y, M, D)
59 | self.today= (Y, M, D, wd)
60 | return True
61 |
62 | def goto_gregorian_day(self,yy, mm, dd):
63 | """Jump to some Hijri day"""
64 | try:
65 | dd += int(self.adjustment) # adjust hijri calendar
66 | Y, M, D = gregorian_to_hijri(yy, mm, dd)
67 | self.goto_hijri_day(Y, M, D)
68 | except:
69 | self.validate()
70 |
71 | return (self.Y,self.M,self.D)
72 |
73 | def goto_hijri_day(self,Y,M,D):
74 | """Jump to some Hijri day"""
75 | self.Y, self.M, self.D = Y, M, D
76 | self.gy,self.gm,self.gd = hijri_to_gregorian(Y, M, D)
77 | self.validate()
78 |
79 | self.mn=hijri_month_days(self.Y, self.M)
80 | self.ms=(7 - self.__ws + hijri_day_of_week(self.Y, self.M, 1))% 7
81 | self.fill_month_days()
82 | return (Y,M,D)
83 |
84 | def fill_month_days(self):
85 | """for internal usage"""
86 | Y, M, D = self.Y,self.M, 1
87 | gy,gm,gd=hijri_to_gregorian(Y,M,D)
88 | gn=gregorian_month_days(gy,gm)
89 | for i in range(6):
90 | for j in range(7):
91 | self.__md[i][j]=""
92 | self.__g_md[i][j]=""
93 | row=0
94 | if self.__direct>0:
95 | col=self.ms
96 | endcol=7
97 | icol=0
98 | else:
99 | col=6-self.ms
100 | endcol=-1
101 | icol=6
102 | for i in range(self.mn):
103 | self.__md[row][col]=i+1
104 | self.__g_md[row][col]=(gd,gm,gy)
105 | gd+=1
106 | if (gd>gn):
107 | gd=1
108 | gm+=1
109 |
110 | if gm>12:
111 | gm=1
112 | gy+=1
113 |
114 | col+=self.__direct
115 | if (col==endcol):
116 | row+=1
117 | col=icol
118 |
119 | def validate(self):
120 | """Make sure the the current Y,M,D is a a valid date, return 0 if it's already valid"""
121 | f=0
122 | if self.M<1:
123 | self.M=12
124 | self.Y-=1
125 | f=1
126 | if self.M>12:
127 | self.M=1
128 | self.Y+=1
129 | f=1
130 | if self.Y<1:
131 | self.Y=1
132 | f=1
133 | if self.D<1:
134 | self.D=1
135 | f=1
136 |
137 | d=hijri_month_days(self.Y, self.M)
138 | if self.D>d :
139 | self.D=d
140 | f=1
141 | return f
142 |
143 | def get_array(self): return tuple(self.__md)
144 | def get_g_array(self): return tuple(self.__g_md)
145 |
146 | def get_week_start(self): return self.__ws
147 | def set_week_start(self,ws):
148 | """Set the first day of the week, 0:Sun, 1:Mon, ..., 6:Sat."""
149 | self.__ws=ws
150 | self.goto_hijri_day(self.Y, self.M, self.D)
151 |
152 | def get_direction(self): return self.__direct
153 | def set_direction(self, direct):
154 | """Set the BiDi RTL direction, 1 direct, -1 reversed"""
155 | self.__direct=direct
156 | self.goto_hijri_day(self.Y, self.M, self.D)
157 |
--------------------------------------------------------------------------------
/home.py:
--------------------------------------------------------------------------------
1 | # Silaty
2 | # Copyright (c) 2018 - 2021 AXeL
3 | # Copyright (c) 2014 - 2015 Jessewb786
4 |
5 | import gi
6 | gi.require_version('Gtk', '3.0')
7 | from gi.repository import GObject, Gtk, Gdk
8 | from hijrical import *
9 | from translate import translate_text as _
10 | import datetime
11 |
12 | class Home(Gtk.Box):
13 | def __init__(self, parent):
14 | Gtk.Box.__init__(self)
15 | self.parent = parent
16 | self.set_orientation(Gtk.Orientation.VERTICAL)
17 | self.set_margin_bottom(6)
18 | self.titlelabel = Gtk.Label(halign=Gtk.Align.FILL, margin_bottom=12, margin_top=12, margin_left=6, margin_right=6)
19 | self.set_title()
20 | self.pack_start(self.titlelabel, False, True, 0)
21 | self.prayers = []
22 | self.nprayers = 0
23 | self.connect("prayers-updated", self.update_prayers_highlight)
24 |
25 | def set_title(self):
26 | # Set the Date in the Title
27 | now_time = datetime.datetime.now().strftime("%H:%M")
28 | now_wd = datetime.datetime.now().strftime("%A")
29 | g_day = datetime.datetime.now().strftime("%d")
30 | g_month = datetime.datetime.now().strftime("%B")
31 | g_year = datetime.datetime.now().strftime("%Y")
32 | g_date = '%s %s %s' % (g_day, _(g_month), g_year)
33 | calc = HijriCal(self.parent.prayertimes.options.hijrical_adjustment)
34 | h_months = ['Muharram', 'Safar', 'Rabi al Awwal', 'Rabi al Akhira', 'Jumada al Ula', 'Jumada al Akhira', 'Rajab', "Sha'ban", 'Ramadan', 'Shawwal', "Dhu al Qa'da", 'Dhu al Hijja']
35 | h_year, h_month, h_day, h_week_day = calc.today
36 | h_date = '%i %s %i' % (h_day, _(h_months[int(h_month-1)]), h_year)
37 |
38 | self.titlelabel.set_label(_('%s - %s, %s / %s') % (now_time, _(now_wd), h_date, g_date))
39 |
40 | def add_prayer(self, prayer, prayertime, colored):
41 | # Prayer Listbox
42 | prayercontainer = Gtk.Box(orientation = Gtk.Orientation.VERTICAL)
43 | prayercontainer.set_size_request(380, 0)
44 | prayerbox = Prayer(prayer, prayertime, colored)
45 | prayerbox.set_halign(Gtk.Align.FILL)
46 | prayerbox.set_valign(Gtk.Align.CENTER)
47 |
48 | if self.nprayers % 2 == 0:
49 | color = 235.0/256.0
50 | prayerbox.override_background_color(Gtk.StateFlags.NORMAL, Gdk.RGBA.from_color(Gdk.Color.from_floats(color,color,color)))
51 | color = 204.0/256.0
52 | prayercontainer.override_background_color(Gtk.StateFlags.NORMAL, Gdk.RGBA.from_color(Gdk.Color.from_floats(color,color,color)))
53 | prayerbox.props.margin_top = 1
54 | prayerbox.props.margin_bottom = 1
55 |
56 | self.nprayers += 1
57 | self.prayers.append(prayerbox)
58 | prayercontainer.pack_start(prayerbox, True, False, 0)
59 | self.pack_start(prayercontainer, False, True, 0)
60 |
61 | def update_prayers_highlight(self, widget, prayername):
62 | print ("DEBUG: received update prayers signal")
63 | for prayer in self.prayers:
64 | if prayer.name == prayername:
65 | prayer.prayerlabel.set_markup(""+prayer.name+"")
66 | prayer.timelabel.set_markup(""+prayer.time+"")
67 | else:
68 | prayer.prayerlabel.set_markup(prayer.name)
69 | prayer.timelabel.set_markup(prayer.time)
70 |
71 | class Prayer(Gtk.Box):
72 | def __init__(self, prayer, prayertime, state):
73 | Gtk.Box.__init__(self)
74 | self.set_orientation(Gtk.Orientation.HORIZONTAL)
75 | self.set_halign(Gtk.Align.FILL)
76 | self.set_valign(Gtk.Align.CENTER)
77 | self._state = state
78 | self._name = prayer
79 | self._time = prayertime
80 |
81 | self.prayerlabel = Gtk.Label(halign=Gtk.Align.START, margin_bottom=6, margin_top=6, margin_left=12, margin_right=12)
82 | self.prayerlabel.set_use_markup(True)
83 |
84 | if state == True:
85 | self.prayerlabel.set_markup(""+prayer+"")
86 | else:
87 | self.prayerlabel.set_label(prayer)
88 |
89 | self.pack_start(self.prayerlabel, True, True, 0)
90 |
91 | self.timelabel = Gtk.Label(label=prayertime, halign=Gtk.Align.END, margin_bottom=6, margin_top=6, margin_right=12, margin_left=12)
92 | self.timelabel.set_use_markup(True)
93 |
94 | if state == True:
95 | self.timelabel.set_markup(""+prayertime+"")
96 | else:
97 | self.timelabel.set_label(prayertime)
98 |
99 | self.pack_end(self.timelabel, True, True, 0)
100 |
101 | @property
102 | def time(self):
103 | return self._time
104 | @time.setter
105 | def time(self, value):
106 | self._time = value
107 |
108 | @property
109 | def name(self):
110 | return self._name
111 |
112 | @name.setter
113 | def name(self, value):
114 | self._name = value
115 |
116 | GObject.type_register(Home)
117 | GObject.signal_new("prayers-updated", Home, GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, [GObject.TYPE_STRING])
118 |
--------------------------------------------------------------------------------
/icons/arrows/arrow-left.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
77 |
--------------------------------------------------------------------------------
/icons/arrows/arrow-right.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
77 |
--------------------------------------------------------------------------------
/icons/hicolor/128x128/apps/silaty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/icons/hicolor/128x128/apps/silaty.png
--------------------------------------------------------------------------------
/icons/hicolor/scalable/silaty-indicator.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
113 |
--------------------------------------------------------------------------------
/icons/sidebar/aboutA.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
99 |
--------------------------------------------------------------------------------
/icons/sidebar/aboutN.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
99 |
--------------------------------------------------------------------------------
/icons/sidebar/calendarA.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
136 |
--------------------------------------------------------------------------------
/icons/sidebar/calendarN.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
136 |
--------------------------------------------------------------------------------
/icons/sidebar/homeA.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
76 |
--------------------------------------------------------------------------------
/icons/sidebar/homeN.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
76 |
--------------------------------------------------------------------------------
/icons/sidebar/notifyA.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
89 |
--------------------------------------------------------------------------------
/icons/sidebar/notifyN.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
102 |
--------------------------------------------------------------------------------
/icons/sidebar/qiblaA.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
97 |
--------------------------------------------------------------------------------
/icons/sidebar/qiblaN.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
97 |
--------------------------------------------------------------------------------
/icons/sidebar/settingsA.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
77 |
--------------------------------------------------------------------------------
/icons/sidebar/settingsN.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
77 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ "$(id -u)" != "0" ]; then
4 | echo “This script must be run as root” 2>&1
5 | exit 1
6 | fi
7 |
8 | sh uninstall.sh
9 |
10 | mkdir /usr/share/silaty
11 | cp -R icons /usr/share/silaty/
12 | cp -R audio /usr/share/silaty/
13 | cp -R data /usr/share/silaty/
14 | cp -R lang /usr/share/silaty/
15 |
16 | cp icons/hicolor/128x128/apps/silaty.svg /usr/share/icons/hicolor/scalable/apps/
17 | chmod 644 /usr/share/icons/hicolor/scalable/apps/silaty.svg
18 |
19 | cp icons/hicolor/128x128/apps/silaty.svg /usr/share/icons/hicolor/128x128/apps/
20 | chmod 644 /usr/share/icons/hicolor/128x128/apps/silaty.svg
21 |
22 | cp icons/hicolor/48x48/apps/silaty.svg /usr/share/icons/hicolor/48x48/apps/
23 | chmod 644 /usr/share/icons/hicolor/48x48/apps/silaty.svg
24 |
25 | cp icons/hicolor/24x24/apps/silaty.svg /usr/share/icons/hicolor/24x24/apps/
26 | chmod 644 /usr/share/icons/hicolor/24x24/apps/silaty.svg
27 |
28 | cp *.py /usr/share/silaty/
29 | chmod 755 -R /usr/share/silaty/
30 |
31 | cp silaty.desktop /etc/xdg/autostart/
32 | chmod 755 /etc/xdg/autostart/silaty.desktop
33 |
34 | cp silaty.desktop /usr/share/applications/
35 | chmod 755 /usr/share/applications/silaty.desktop
36 |
37 | ln -s /usr/share/silaty/silaty-indicator.py /usr/local/bin/silaty-indicator
38 | chmod 755 /usr/local/bin/silaty-indicator
39 |
40 | gtk-update-icon-cache
41 |
--------------------------------------------------------------------------------
/lang/ar.json:
--------------------------------------------------------------------------------
1 | {
2 | "Silaty": "صلاتي",
3 | "Fajr": "الفجر",
4 | "Shuruk": "الشروق",
5 | "Dhuhr": "الظهر",
6 | "Asr": "العصر",
7 | "Maghrib": "المغرب",
8 | "Isha": "العشاء",
9 | "System": "إعدادات التطبيق",
10 | "Start Minimized:": "إخفاء نافذة التطبيق عند بدء التشغيل:",
11 | "Daylight Saving Time:": "تفعيل التوقيت الصيفي:",
12 | "Clock Format:": "تنسيق الوقت:",
13 | "12h": "12 ساعة",
14 | "24h": "24 ساعة",
15 | "Adjust Hijri Calendar:": "ضبط التقويم الهجري:",
16 | "Language:": "اللغة:",
17 | "English": "الإنجليزية",
18 | "French": "الفرنسية",
19 | "Arabic": "العربية",
20 | "Spanish": "الإسبانية",
21 | "Notifications": "الإشعارات",
22 | "Show Time left with Icon:": "عرض الوقت المتبقي بجانب الأيقونة:",
23 | "Enable audio notifications:": "تفعيل الإشعارات الصوتية:",
24 | "Time before notification:": "الوقت قبل الإشعار:",
25 | "Fajr Adhan:": "أذان الفجر:",
26 | "Normal Adhan:": "أذان عادي:",
27 | "Jurisprudence": "الفقه",
28 | "Calculation Method:": "طريقة الحساب:",
29 | "Makkah": "مكة المكرمة",
30 | "Egypt": "مصر",
31 | "Karachi": "كراتشي",
32 | "ISNA": "الجمعية الإسلامية لأمريكا الشمالية",
33 | "MWL": "رابطة العالم الإسلامي",
34 | "Madhab:": "المذهب:",
35 | "Hanafi": "حنفي",
36 | "Default": "افتراضي",
37 | "Location": "الموقع",
38 | "City:": "المدينة:",
39 | "Latitude:": "خط العرض:",
40 | "Longitude:": "خط الطول:",
41 | "Time Zone:": "النطاق الزمني:",
42 | "Location: %s": "الموقع: %s",
43 | "Qibla is %.2f° from True North": "القبلة على بعد %.2f درجة من الشمال الحقيقي",
44 | "Fajr\t\t\t\t\t%s": "الفجر\t\t\t\t\t%s",
45 | "Shuruk\t\t\t%s": "الشروق\t\t\t\t%s",
46 | "Dhuhr\t\t\t\t%s": "الظهر\t\t\t\t\t%s",
47 | "Asr\t\t\t\t\t%s": "العصر\t\t\t\t\t%s",
48 | "Maghrib\t\t\t\t%s": "المغرب\t\t\t\t\t%s",
49 | "Isha\t\t\t\t\t%s": "العشاء\t\t\t\t\t%s",
50 | "Next Prayer": "الصلاة التالية",
51 | "About": "حول التطبيق",
52 | "Settings": "الإعدادات",
53 | "Quit": "خروج",
54 | "%s until %s": "%s حتى صلاة %s",
55 | "%s in %s": "%s بعد %s",
56 | "%s Hours": "%s ساعة",
57 | "%s Minutes": "%s دقيقة",
58 | "%s Hours and %s Minutes": "%s ساعة و %s دقيقة",
59 | "%shr": "%s ساعة",
60 | "%smin": "%s دقيقة",
61 | "%shr %smin": "%s ساعة %s دقيقة",
62 | "GitHub Project Page": "صفحة المشروع على GitHub",
63 | "A neat Prayer Time Reminder App.\n Simple and complete so no prayer is missed": "تطبيق أوقات الصلاة.\n بسيط و شامل حتى لا تفوتك أي صلاة",
64 | "Copyright © %s Silaty Team": "حقوق النشر © %s فريق صلاتي",
65 | "Silaty needs to be restarted, restart now?": "يحتاج التطبيق إلى إعادة تشغيل، إعادة التشغيل الآن؟",
66 | "Hijri:": "هجري:",
67 | "Sunday": "الأحد",
68 | "Monday": "الإثنين",
69 | "Tuesday": "الثلاثاء",
70 | "Wednesday": "الأربعاء",
71 | "Thursday": "الخميس",
72 | "Friday": "الجمعة",
73 | "Saturday": "السبت",
74 | "SundayShort": "ح",
75 | "MondayShort": "ن",
76 | "TuesdayShort": "ث",
77 | "WednesdayShort": "ر",
78 | "ThursdayShort": "خ",
79 | "FridayShort": "ج",
80 | "SaturdayShort": "س",
81 | "January": "يناير",
82 | "February": "فبراير",
83 | "March": "مارس",
84 | "April": "أبريل",
85 | "May": "مايو",
86 | "June": "يونيو",
87 | "July": "يوليو",
88 | "August": "أغسطس",
89 | "September": "سبتمبر",
90 | "October": "أكتوبر",
91 | "November": "نوفمبر",
92 | "December": "ديسمبر",
93 | "Muharram": "محرم",
94 | "Safar": "صفر",
95 | "Rabi al Awwal": "ربيع الأول",
96 | "Rabi al Akhira": "ربيع الآخر",
97 | "Jumada al Ula": "جمادى الأولى",
98 | "Jumada al Akhira": "جمادى الآخرة",
99 | "Rajab": "رجب",
100 | "Sha'ban": "شعبان",
101 | "Ramadhan": "رمضان",
102 | "Shawwal": "شوال",
103 | "Dhu al Qa'da": "ذو القعدة",
104 | "Dhu al Hijja": "ذو الحجة",
105 | "Qibla direction :": "اتجاه القبلة :",
106 | "Country : %s": "الدولة : %s",
107 | "City : %s": "المدينة : %s",
108 | "Search:": "بحث:",
109 | "Check your location on %s": "يمكنك التحقق من موقعك على %s",
110 | "Get Ready": "إستعد",
111 | "%s minutes left until the %s prayer.": "%s دقائق متبقية حتى صلاة %s.",
112 | "Prayer time for %s": "وقت صلاة %s",
113 | "It's time for the %s prayer.": "حان الوقت لصلاة %s.",
114 | "%s, %s": "%s، %s",
115 | "%s - %s, %s / %s": "%s - %s، %s / %s",
116 | "AM": "ص",
117 | "PM": "م",
118 | "Apply": "ضبط",
119 | "Cancel": "إلغاء"
120 | }
121 |
--------------------------------------------------------------------------------
/lang/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "Silaty": "Silaty",
3 | "Fajr": "Fajr",
4 | "Shuruk": "Shuruk",
5 | "Dhuhr": "Dhuhr",
6 | "Asr": "Asr",
7 | "Maghrib": "Maghrib",
8 | "Isha": "Isha",
9 | "System": "System",
10 | "Start Minimized:": "Start Minimized:",
11 | "Daylight Saving Time:": "Daylight Saving Time:",
12 | "Clock Format:": "Clock Format:",
13 | "12h": "12h",
14 | "24h": "24h",
15 | "Adjust Hijri Calendar:": "Adjust Hijri Calendar:",
16 | "Language:": "Language:",
17 | "English": "English",
18 | "French": "French",
19 | "Arabic": "Arabic",
20 | "Spanish": "Spanish",
21 | "Notifications": "Notifications",
22 | "Show Time left with Icon:": "Show Time left with Icon:",
23 | "Enable audio notifications:": "Enable audio notifications:",
24 | "Time before notification:": "Time before notification:",
25 | "Fajr Adhan:": "Fajr Adhan:",
26 | "Normal Adhan:": "Normal Adhan:",
27 | "Jurisprudence": "Jurisprudence",
28 | "Calculation Method:": "Calculation Method:",
29 | "Makkah": "Makkah",
30 | "Egypt": "Egypt",
31 | "Karachi": "Karachi",
32 | "ISNA": "ISNA",
33 | "MWL": "MWL",
34 | "Madhab:": "Madhab:",
35 | "Hanafi": "Hanafi",
36 | "Default": "Default",
37 | "Location": "Location",
38 | "City:": "City:",
39 | "Latitude:": "Latitude:",
40 | "Longitude:": "Longitude:",
41 | "Time Zone:": "Time Zone:",
42 | "Location: %s": "Location: %s",
43 | "Qibla is %.2f° from True North": "Qibla is %.2f° from True North",
44 | "Fajr\t\t\t\t\t%s": "Fajr\t\t\t\t\t%s",
45 | "Shuruk\t\t\t%s": "Shuruk\t\t\t%s",
46 | "Dhuhr\t\t\t\t%s": "Dhuhr\t\t\t\t%s",
47 | "Asr\t\t\t\t\t%s": "Asr\t\t\t\t\t%s",
48 | "Maghrib\t\t\t\t%s": "Maghrib\t\t\t\t%s",
49 | "Isha\t\t\t\t\t%s": "Isha\t\t\t\t\t%s",
50 | "Next Prayer": "Next Prayer:",
51 | "About": "About",
52 | "Settings": "Settings",
53 | "Quit": "Quit",
54 | "%s until %s": "%s until %s",
55 | "%s in %s": "%s in %s",
56 | "%s Hours": "%s Hours",
57 | "%s Minutes": "%s Minutes",
58 | "%s Hours and %s Minutes": "%s Hours and %s Minutes",
59 | "%shr": "%shr",
60 | "%smin": "%smin",
61 | "%shr %smin": "%shr %smin",
62 | "GitHub Project Page": "GitHub Project Page",
63 | "A neat Prayer Time Reminder App.\n Simple and complete so no prayer is missed": "A neat Prayer Time Reminder App.\n Simple and complete so no prayer is missed",
64 | "Copyright © %s Silaty Team": "Copyright © %s Silaty Team",
65 | "Silaty needs to be restarted, restart now?": "Silaty needs to be restarted, restart now?",
66 | "Hijri:": "Hijri:",
67 | "Sunday": "Sunday",
68 | "Monday": "Monday",
69 | "Tuesday": "Tuesday",
70 | "Wednesday": "Wednesday",
71 | "Thursday": "Thursday",
72 | "Friday": "Friday",
73 | "Saturday": "Saturday",
74 | "SundayShort": "S",
75 | "MondayShort": "M",
76 | "TuesdayShort": "T",
77 | "WednesdayShort": "W",
78 | "ThursdayShort": "T",
79 | "FridayShort": "F",
80 | "SaturdayShort": "S",
81 | "January": "January",
82 | "February": "February",
83 | "March": "March",
84 | "April": "April",
85 | "May": "May",
86 | "June": "June",
87 | "July": "July",
88 | "August": "August",
89 | "September": "September",
90 | "October": "October",
91 | "November": "November",
92 | "December": "December",
93 | "Muharram": "Muharram",
94 | "Safar": "Safar",
95 | "Rabi al Awwal": "Rabi al Awwal",
96 | "Rabi al Akhira": "Rabi al Akhira",
97 | "Jumada al Ula": "Jumada al Ula",
98 | "Jumada al Akhira": "Jumada al Akhira",
99 | "Rajab": "Rajab",
100 | "Sha'ban": "Sha'ban",
101 | "Ramadhan": "Ramadhan",
102 | "Shawwal": "Shawwal",
103 | "Dhu al Qa'da": "Dhu al Qa'da",
104 | "Dhu al Hijja": "Dhu al Hijja",
105 | "Qibla direction :": "Qibla direction :",
106 | "Country : %s": "Country : %s",
107 | "City : %s": "City : %s",
108 | "Search:": "Search:",
109 | "Check your location on %s": "Check your location on %s",
110 | "Get Ready": "Get Ready",
111 | "%s minutes left until the %s prayer.": "%s minutes left until the %s prayer.",
112 | "Prayer time for %s": "Prayer time for %s",
113 | "It's time for the %s prayer.": "It's time for the %s prayer.",
114 | "%s, %s": "%s، %s",
115 | "%s - %s, %s / %s": "%s - %s، %s / %s",
116 | "AM": "AM",
117 | "PM": "PM",
118 | "Apply": "Apply",
119 | "Cancel": "Cancel"
120 | }
121 |
--------------------------------------------------------------------------------
/lang/es.json:
--------------------------------------------------------------------------------
1 | {
2 | "Silaty": "Silaty",
3 | "Fajr": "Fajr",
4 | "Shuruk": "Amanecer",
5 | "Dhuhr": "Dhuhr",
6 | "Asr": "Asr",
7 | "Maghrib": "Maghrib",
8 | "Isha": "Isha",
9 | "System": "Systema",
10 | "Start Minimized:": "Inicial Minimizado:",
11 | "Daylight Saving Time:": "Horario de verano:",
12 | "Clock Format:": "Formato de reloj:",
13 | "12h": "12 horas",
14 | "24h": "24 horas",
15 | "Adjust Hijri Calendar:": "Ajustar el Calendario Hijri:",
16 | "Language:": "Idioma:",
17 | "English": "Ingles",
18 | "French": "Frances",
19 | "Arabic": "Arabe",
20 | "Spanish": "Español",
21 | "Notifications": "Notificaciones",
22 | "Show Time left with Icon:": "Monstrar tiempo restante con icono:",
23 | "Enable audio notifications:": "Activar las notificaciones audio:",
24 | "Time before notification:": "Tiempo antes de la notificacion:",
25 | "Fajr Adhan:": "Adhan de Fajr:",
26 | "Normal Adhan:": "Adhan normal:",
27 | "Jurisprudence": "Jurisprudencia",
28 | "Calculation Method:": "Método de cálculo:",
29 | "Makkah": "Meca",
30 | "Egypt": "Egipto",
31 | "Karachi": "Karachi",
32 | "ISNA": "ISNA (Norteamérica)",
33 | "MWL": "Liga Mundial Musulmana",
34 | "Madhab:": "Madhab:",
35 | "Hanafi": "Hanafi",
36 | "Default": "Defecto",
37 | "Location": "Locacion",
38 | "City:": "Ciudad:",
39 | "Latitude:": "Latitud:",
40 | "Longitude:": "Longitud:",
41 | "Time Zone:": "Zona horaria:",
42 | "Location: %s": "Locacion: %s",
43 | "Qibla is %.2f° from True North": "La Qibla esta a %.2f del verdadero Norte",
44 | "Fajr\t\t\t\t\t%s": "Fajr\t\t\t\t\t%s",
45 | "Shuruk\t\t\t%s": "Amanecer\t\t\t\t%s",
46 | "Dhuhr\t\t\t\t%s": "Dhurh\t\t\t\t%s",
47 | "Asr\t\t\t\t\t%s": "Asr\t\t\t\t\t%s",
48 | "Maghrib\t\t\t\t%s": "Maghrib\t\t\t\t%s",
49 | "Isha\t\t\t\t\t%s": "Isha\t\t\t\t\t%s",
50 | "Next Prayer": "Proximo rezo:",
51 | "About": "À propos",
52 | "Settings": "Acerca de",
53 | "Quit": "Quitar",
54 | "%s until %s": "%s antes de %s",
55 | "%s in %s": "%s en %s",
56 | "%s Hours": "%s Horas",
57 | "%s Minutes": "%s Minutos",
58 | "%s Hours and %s Minutes": "%s Heros et %s Minutos",
59 | "%shr": "%shoras",
60 | "%smin": "%smin",
61 | "%shr %smin": "%shoras %smin",
62 | "GitHub Project Page": "Pagina GitHub del Proyecto",
63 | "A neat Prayer Time Reminder App.\n Simple and complete so no prayer is missed": "Una excelente aplicación para los tiempos de oracion.\n Simple y completa para que no se olvide ninguna oración",
64 | "Copyright © %s Silaty Team": "Copyright © %s Silaty Team",
65 | "Silaty needs to be restarted, restart now?": "Silaty necesita ser reiniciado, ¿reiniciar ahora?",
66 | "Hijri:": "Hijri:",
67 | "Sunday": "Domindo",
68 | "Monday": "Lunes",
69 | "Tuesday": "Martes",
70 | "Wednesday": "Miercoles",
71 | "Thursday": "Jueves",
72 | "Friday": "Viernes",
73 | "Saturday": "Sabado",
74 | "SundayShort": "D",
75 | "MondayShort": "L",
76 | "TuesdayShort": "Ma",
77 | "WednesdayShort": "Mi",
78 | "ThursdayShort": "J",
79 | "FridayShort": "V",
80 | "SaturdayShort": "S",
81 | "January": "Enero",
82 | "February": "Febrero",
83 | "March": "Marzo",
84 | "April": "April",
85 | "May": "mayo",
86 | "June": "Junio",
87 | "July": "Julio",
88 | "August": "Agosto",
89 | "September": "Septiembre",
90 | "October": "Octubre",
91 | "November": "Noviembre",
92 | "December": "Diciembre",
93 | "Muharram": "Muharram",
94 | "Safar": "Safar",
95 | "Rabi al Awwal": "Rabi al Awwal",
96 | "Rabi al Akhira": "Rabi al Akhira",
97 | "Jumada al Ula": "Jumada al Ula",
98 | "Jumada al Akhira": "Jumada al Akhira",
99 | "Rajab": "Rajab",
100 | "Sha'ban": "Sha'ban",
101 | "Ramadhan": "Ramadhan",
102 | "Shawwal": "Shawwal",
103 | "Dhu al Qa'da": "Dhu al Qa'da",
104 | "Dhu al Hijja": "Dhu al Hijja",
105 | "Qibla direction :": "Direccion de la Qibla :",
106 | "Country : %s": "País : %s",
107 | "City : %s": "Ciudad : %s",
108 | "Search:": "Burcar:",
109 | "Check your location on %s": "Consulta tu ubicación sobre %s",
110 | "Get Ready": "Prepararse",
111 | "%s minutes left until the %s prayer.": "%s minutos antes de la oracion de %s.",
112 | "Prayer time for %s": "Hora de la oracian para %s",
113 | "It's time for the %s prayer.": "Es la hora de la oracion %s.",
114 | "%s, %s": "%s، %s",
115 | "%s - %s, %s / %s": "%s - %s، %s / %s",
116 | "AM": "AM",
117 | "PM": "PM",
118 | "Apply": "Aplicar",
119 | "Cancel": "Cancelar"
120 | }
121 |
--------------------------------------------------------------------------------
/lang/fr.json:
--------------------------------------------------------------------------------
1 | {
2 | "Silaty": "Silaty",
3 | "Fajr": "Fajr",
4 | "Shuruk": "Lever du Soleil",
5 | "Dhuhr": "Dhuhr",
6 | "Asr": "Asr",
7 | "Maghrib": "Maghrib",
8 | "Isha": "Isha",
9 | "System": "Système",
10 | "Start Minimized:": "Lancer l'application minimisée",
11 | "Daylight Saving Time:": "Heure d'été:",
12 | "Clock Format:": "Format de l'heure",
13 | "12h": "12 heures",
14 | "24h": "24 heures",
15 | "Adjust Hijri Calendar:": "Ajuster le calendrier Hijri",
16 | "Language:": "Langue:",
17 | "English": "Anglais",
18 | "French": "Français",
19 | "Arabic": "Arabe",
20 | "Spanish": "Espagnol",
21 | "Notifications": "Notifications",
22 | "Show Time left with Icon:": "Montrer temps restant avec icone:",
23 | "Enable audio notifications:": "Activer les notifications audio:",
24 | "Time before notification:": "Temps avant la notification:",
25 | "Fajr Adhan:": "Adhan de Fajr:",
26 | "Normal Adhan:": "Adhan normal:",
27 | "Jurisprudence": "Jurisprudence",
28 | "Calculation Method:": "Methode de Calcul:",
29 | "Makkah": "Makkah",
30 | "Egypt": "Egypte",
31 | "Karachi": "Karachi",
32 | "ISNA": "ISNA (Amérique du Nord)",
33 | "MWL": "Ligue Musulmane Mondiale",
34 | "Madhab:": "Madhab:",
35 | "Hanafi": "Hanafi",
36 | "Default": "Défaut",
37 | "Location": "Location",
38 | "City:": "Ville:",
39 | "Latitude:": "Latitude:",
40 | "Longitude:": "Longitude:",
41 | "Time Zone:": "Fuseau Horaire:",
42 | "Location: %s": "Location: %s",
43 | "Qibla is %.2f° from True North": "La Qibla est à %.2f du vrai Nord",
44 | "Fajr\t\t\t\t\t%s": "Fajr\t\t\t\t\t%s",
45 | "Shuruk\t\t\t%s": "Lever du Soleil\t\t\t\t%s",
46 | "Dhuhr\t\t\t\t%s": "Dhurh\t\t\t\t%s",
47 | "Asr\t\t\t\t\t%s": "Asr\t\t\t\t\t%s",
48 | "Maghrib\t\t\t\t%s": "Maghrib\t\t\t\t%s",
49 | "Isha\t\t\t\t\t%s": "Isha\t\t\t\t\t%s",
50 | "Next Prayer": "Prochaine Prière:",
51 | "About": "À propos",
52 | "Settings": "Options",
53 | "Quit": "Quitter",
54 | "%s until %s": "%s avant %s",
55 | "%s in %s": "%s dans %s",
56 | "%s Hours": "%s Heures",
57 | "%s Minutes": "%s Minutes",
58 | "%s Hours and %s Minutes": "%s Heures et %s Minutes",
59 | "%shr": "%sheures",
60 | "%smin": "%smin",
61 | "%shr %smin": "%sheures %smin",
62 | "GitHub Project Page": "Page GitHub du Projet",
63 | "A neat Prayer Time Reminder App.\n Simple and complete so no prayer is missed": "Une application polie de rappel pour le temps de Prièr.\n Simple et complète pour qu'aucune prière ne soit ratée",
64 | "Copyright © %s Silaty Team": "Copyright © %s Silaty Team",
65 | "Silaty needs to be restarted, restart now?": "Silaty a besoin d'être redémarrée, redémarrer maintenent ?",
66 | "Hijri:": "Hijri:",
67 | "Sunday": "Dimanche",
68 | "Monday": "Lundi",
69 | "Tuesday": "Mardi",
70 | "Wednesday": "Mercredi",
71 | "Thursday": "Jeudi",
72 | "Friday": "Vendredi",
73 | "Saturday": "Saturday",
74 | "SundayShort": "D",
75 | "MondayShort": "L",
76 | "TuesdayShort": "Ma",
77 | "WednesdayShort": "Me",
78 | "ThursdayShort": "J",
79 | "FridayShort": "V",
80 | "SaturdayShort": "S",
81 | "January": "Janvier",
82 | "February": "Février",
83 | "March": "Mars",
84 | "April": "Avril",
85 | "May": "Mai",
86 | "June": "Juin",
87 | "July": "Juillet",
88 | "August": "Aôut",
89 | "September": "Septembre",
90 | "October": "Octobre",
91 | "November": "Novembre",
92 | "December": "Decembre",
93 | "Muharram": "Muharram",
94 | "Safar": "Safar",
95 | "Rabi al Awwal": "Rabi al Awwal",
96 | "Rabi al Akhira": "Rabi al Akhira",
97 | "Jumada al Ula": "Jumada al Ula",
98 | "Jumada al Akhira": "Jumada al Akhira",
99 | "Rajab": "Rajab",
100 | "Sha'ban": "Sha'ban",
101 | "Ramadhan": "Ramadhan",
102 | "Shawwal": "Shawwal",
103 | "Dhu al Qa'da": "Dhu al Qa'da",
104 | "Dhu al Hijja": "Dhu al Hijja",
105 | "Qibla direction :": "Direction de la Qibla :",
106 | "Country : %s": "Pays : %s",
107 | "City : %s": "Ville : %s",
108 | "Search:": "Chercher:",
109 | "Check your location on %s": "Vérifiez votre location sur %s",
110 | "Get Ready": "Préparez-vous",
111 | "%s minutes left until the %s prayer.": "%s minutes avant la prière de %s.",
112 | "Prayer time for %s": "Temps de prière pour %s",
113 | "It's time for the %s prayer.": "C'est le temps pour la prière de %s.",
114 | "%s, %s": "%s، %s",
115 | "%s - %s, %s / %s": "%s - %s، %s / %s",
116 | "AM": "AM",
117 | "PM": "PM",
118 | "Apply": "Appliquer",
119 | "Cancel": "Annuler"
120 | }
121 |
--------------------------------------------------------------------------------
/location.py:
--------------------------------------------------------------------------------
1 | # Silaty
2 | # Copyright (c) 2018 - 2021 AXeL
3 | # Copyright (c) 2014 - 2015 Jessewb786
4 |
5 | import gi
6 | gi.require_version('Gtk', '3.0')
7 | from gi.repository import Gtk
8 | from translate import translate_text as _
9 | import os
10 | try:
11 | import xml.etree.cElementTree as ET # C implementation is much faster
12 | except ImportError:
13 | import xml.etree.ElementTree as ET
14 |
15 | class TimeZone():
16 |
17 | def __init__(self, zone_name, value):
18 | self.zone_name = zone_name
19 | self.value = value
20 |
21 | class Country():
22 |
23 | def __init__(self, name, timezone):
24 | self.name = name
25 | self.timezone = timezone
26 |
27 | class Location():
28 |
29 | def __init__(self, num, name, coordinates, country, is_city):
30 | self.num = num
31 | self.name = name
32 | self.coordinates = coordinates
33 | self.country = country
34 | self.is_city = is_city
35 |
36 | def get_latitude(self):
37 | if self.coordinates is None:
38 | return None
39 | else:
40 | coordinates = self.coordinates.split(' ')
41 | return float(coordinates[0])
42 |
43 | def get_longitude(self):
44 | if self.coordinates is None:
45 | return None
46 | else:
47 | coordinates = self.coordinates.split(' ')
48 | if len(coordinates) <= 1:
49 | return None
50 | else:
51 | return float(coordinates[1])
52 |
53 | class LocationDialog(Gtk.Dialog):
54 |
55 | def __init__(self, parent, title='Silaty'):
56 | Gtk.Dialog.__init__(self, modal=True, transient_for=parent, title=_(title), flags=Gtk.DialogFlags.DESTROY_WITH_PARENT)
57 | self.parent = parent
58 | self.set_border_width(10)
59 | self.set_resizable(False)
60 | self.connect('delete-event', self.hide_dialog)
61 | self.connect('response', self.hide_dialog)
62 | self.locations = []
63 | self.locations_count = 0
64 | # Location
65 | content_area = self.get_content_area()
66 | content_area.set_spacing(5)
67 | scrolledwindow = Gtk.ScrolledWindow()
68 | scrolledwindow.set_size_request(150, 250)
69 | content_area.add(scrolledwindow)
70 | self.treestore = Gtk.TreeStore(str, int)
71 | self.parse_locations()
72 | treemodelsort = Gtk.TreeModelSort(self.treestore)
73 | treemodelsort.set_sort_column_id(0, Gtk.SortType.ASCENDING)
74 | self.treeview = Gtk.TreeView()
75 | self.treeview.set_model(treemodelsort)
76 | scrolledwindow.add(self.treeview)
77 | cellrenderertext = Gtk.CellRendererText()
78 | treeviewcolumn = Gtk.TreeViewColumn(_('Location'), cellrenderertext, text=0)
79 | self.treeview.append_column(treeviewcolumn)
80 | #self.treeview.set_headers_visible(False)
81 | treeselection = self.treeview.get_selection()
82 | treeselection.set_mode(Gtk.SelectionMode.SINGLE)
83 | treeselection.connect('changed', self.on_selection_changed)
84 | # Search
85 | searchbox = Gtk.Box(halign=Gtk.Align.FILL, spacing=10)
86 | searchlabel = Gtk.Label(_('Search:'), halign=Gtk.Align.START)
87 | searchbox.pack_start(searchlabel, False, False, 0)
88 | searchentry = Gtk.Entry(halign=Gtk.Align.FILL)
89 | searchentry.connect('changed', self.on_search_entry_changed)
90 | self.treeview.set_search_entry(searchentry)
91 | self.treeview.set_search_equal_func(self.search_function)
92 | self.treeview.set_search_column(0)
93 | searchbox.pack_start(searchentry, True, True, 0)
94 | content_area.add(searchbox)
95 | # Help
96 | helpbox = Gtk.Box(halign=Gtk.Align.FILL, spacing=3, margin=10)
97 | helpimage = Gtk.Image(icon_name='system-help')
98 | helpbox.pack_start(helpimage, False, False, 0)
99 | helplabel = Gtk.Label(_('Check your location on %s') % 'www.islamicfinder.org', use_markup=True)
100 | helpbox.pack_start(helplabel, True, True, 0)
101 | content_area.add(helpbox)
102 | # Buttons
103 | self.action_area.set_layout(Gtk.ButtonBoxStyle.END)
104 | self.apply_button = Gtk.Button(_('Apply'))
105 | self.apply_button.set_sensitive(False)
106 | self.apply_button.connect('clicked', self.on_apply_button_clicked)
107 | cancel_button = Gtk.Button(_('Cancel'))
108 | cancel_button.connect('clicked', self.on_cancel_button_clicked)
109 | self.add_action_widget(self.apply_button, Gtk.ResponseType.OK)
110 | self.add_action_widget(cancel_button, Gtk.ResponseType.CANCEL)
111 | self.show_all()
112 |
113 | def hide_dialog(self, widget, response):
114 | self.hide()
115 | return True
116 |
117 | def on_apply_button_clicked(self, widget):
118 | location_num = self.get_selected_location()
119 | location = self.get_location(location_num)
120 | if location is not None:
121 | self.parent.lock_location_updates = True
122 | self.parent.prayertimes.options.country = location.country.name
123 | self.parent.prayertimes.options.city = location.name
124 | self.parent.cityentry.set_text(location.name)
125 | latitude = location.get_latitude()
126 | longitude = location.get_longitude()
127 | timezone = location.country.timezone
128 | if latitude is not None:
129 | self.parent.latentry.set_value(latitude)
130 | if longitude is not None:
131 | self.parent.longentry.set_value(longitude)
132 | if timezone is not None:
133 | self.parent.tzentry.set_value(timezone.value)
134 | self.parent.update_location()
135 | self.parent.lock_location_updates = False
136 |
137 | def on_cancel_button_clicked(self, widget):
138 | pass
139 |
140 | def on_search_entry_changed(self, widget):
141 | if not widget.get_text():
142 | self.apply_button.set_sensitive(False)
143 |
144 | def get_location(self, location_num):
145 | if location_num is not None:
146 | for location in self.locations:
147 | if location.num == location_num:
148 | return location
149 |
150 | return None
151 |
152 | def is_location(self, location_num):
153 | if self.get_location(location_num) is None:
154 | return False
155 | else:
156 | return True
157 |
158 | def get_selected_location(self, selection = None):
159 | if selection is None:
160 | selection = self.treeview.get_selection()
161 | model, tree_iter = selection.get_selected()
162 | if tree_iter and not model.iter_has_child(tree_iter): # a location should not have children
163 | value = model.get_value(tree_iter, 1) # 0 => location name, 1 => location num
164 | return value
165 | else:
166 | return None
167 |
168 | def on_selection_changed(self, selection):
169 | location_num = self.get_selected_location(selection)
170 | if self.is_location(location_num):
171 | self.apply_button.set_sensitive(True)
172 | else:
173 | self.apply_button.set_sensitive(False)
174 |
175 | def toggle_rows(self, row, key, column):
176 | for child in row.iterchildren():
177 | if key.lower() in list(child)[column].lower():
178 | self.treeview.expand_to_path(row.path)
179 | return True
180 | else:
181 | if self.toggle_rows(child, key, column):
182 | return True
183 | self.treeview.collapse_row(row.path)
184 |
185 | return False
186 |
187 | # @see https://stackoverflow.com/questions/23355866/user-search-collapsed-rows-in-a-gtk-treeview
188 | def search_function(self, model, column, key, rowiter):
189 | row = model[rowiter]
190 | if key.lower() in list(row)[column-2].lower():
191 | return False # Search matches
192 |
193 | # Search in child rows. If one of the rows matches, expand the row so that it will be open in later checks.
194 | self.toggle_rows(row, key, column-2)
195 |
196 | return True # Search does not match
197 |
198 | def add_location(self, location, country, is_city = False):
199 | name = location[0].text
200 | location_coordinates = location.find('coordinates')
201 | if location_coordinates is not None:
202 | coordinates = location_coordinates.text
203 | else:
204 | print ('WARNING: %s > %s has no coordinates.' % (country.name, name))
205 | coordinates = None
206 | self.locations_count += 1
207 | new_location = Location(self.locations_count, name, coordinates, country, is_city)
208 | # add new location
209 | self.locations.append(new_location)
210 |
211 | def parse_locations(self):
212 | # Parse XML file
213 | tree = ET.parse(os.path.dirname(os.path.realpath(__file__)) + '/data/Locations.xml')
214 | root = tree.getroot()
215 | for child in root:
216 | if child.tag == 'region':
217 | region_name = child.find('name').text
218 | #print ('%s' % region_name)
219 | region_node = self.treestore.append(None, [region_name, 0])
220 | for region_child in child:
221 | if region_child.tag == 'country':
222 | country_name = region_child.find('name').text
223 | #print ('├── %s' % country_name)
224 | timezones = region_child.find('timezones')
225 | if timezones is not None:
226 | zone = timezones[0].attrib['id']
227 | value = float(timezones[0].attrib['value'])
228 | timezone = TimeZone(zone, value)
229 | else:
230 | print ('WARNING: %s has no timezone.' % (country_name))
231 | timezone = None
232 | country = Country(country_name, timezone)
233 | country_node = self.treestore.append(region_node, [country_name, 0])
234 | for country_child in region_child:
235 | if country_child.tag == 'location':
236 | location_name = country_child.find('name').text
237 | #print ('│ ├── %s' % location_name)
238 | self.add_location(country_child, country)
239 | self.treestore.append(country_node, [location_name, self.locations_count])
240 | elif country_child.tag == 'city':
241 | city_name = country_child.find('name').text
242 | #print ('│ ├── %s' % city_name)
243 | self.add_location(country_child, country, True)
244 | self.treestore.append(country_node, [city_name, self.locations_count])
245 | elif country_child.tag == 'state':
246 | state_name = country_child.find('name').text
247 | #print ('│ ├── %s' % state_name)
248 | state_node = self.treestore.append(country_node, [state_name, 0])
249 | for state_child in country_child:
250 | if state_child.tag == 'location':
251 | location_name = state_child.find('name').text
252 | #print ('│ │ ├── %s' % location_name)
253 | self.add_location(state_child, country)
254 | self.treestore.append(state_node, [location_name, self.locations_count])
255 | elif state_child.tag == 'city':
256 | city_name = state_child.find('name').text
257 | #print ('│ │ ├── %s' % city_name)
258 | self.add_location(state_child, country, True)
259 | self.treestore.append(state_node, [city_name, self.locations_count])
260 |
--------------------------------------------------------------------------------
/options.py:
--------------------------------------------------------------------------------
1 | # Silaty
2 | # Copyright (c) 2018 - 2021 AXeL
3 | # Copyright (c) 2014 - 2015 Jessewb786
4 |
5 | import configparser
6 | import os
7 | import datetime
8 | from translate import languages
9 |
10 | class Calendar(object):
11 | UmmAlQuraUniv, \
12 | EgyptianGeneralAuthorityOfSurvey,\
13 | UnivOfIslamicSciencesKarachi,\
14 | IslamicSocietyOfNorthAmerica,\
15 | MuslimWorldLeague = range(5)
16 |
17 | class Madhab(object):
18 | Default, Hanafi = 0, 1
19 |
20 | class Options:
21 | def __init__(self):
22 | print ("DEBUG: Initializing the Options module @", (str(datetime.datetime.now())))
23 |
24 | cparse = configparser.ConfigParser()
25 | cparse.read([os.path.expanduser('~/.silaty')])
26 |
27 | try:
28 | self._city = cparse.get('DEFAULT', 'city')
29 | self._country = cparse.get('DEFAULT', 'country')
30 | self._calcmethodname = cparse.get('DEFAULT', 'calculation-method')
31 | self._madhab = cparse.get('DEFAULT', 'madhab')
32 | self._clockformat = cparse.get('DEFAULT', 'clock-format')
33 | self._latitude = cparse.get('DEFAULT', 'latitude')
34 | self._longitude = cparse.get('DEFAULT', 'longitude')
35 | self._timezone = cparse.get('DEFAULT', 'timezone')
36 | self._notif = cparse.get('DEFAULT', 'notif')
37 | self._iconlabel = cparse.get('DEFAULT', 'iconlabel')
38 | self._startminimized = cparse.get('DEFAULT', 'minimized')
39 | self._fajradhan = cparse.get('DEFAULT', 'fajr-adhan')
40 | self._normaladhan = cparse.get('DEFAULT', 'normal-adhan')
41 | self._audionotifications = cparse.get('DEFAULT', 'audio-notifications')
42 | self._daylightsavingtime = cparse.get('DEFAULT', 'daylight-saving-time')
43 | self._hijricaladjustment = cparse.get('DEFAULT', 'hijrical-adjustment')
44 | self._language = cparse.get('DEFAULT', 'language')
45 |
46 | except configparser.NoOptionError:
47 | print ("DEBUG: No configration file using default settings")
48 | self._city = 'Makkah'
49 | self._country = 'Saudi Arabia'
50 | self._latitude = '21.25'
51 | self._longitude = '39.49'
52 | self._timezone = '3'
53 | self._calcmethodname = 'Makkah'
54 | self._madhab = 'Default'
55 | self._clockformat = '24h'
56 | self._notif = '10'
57 | self._iconlabel = '1'
58 | self._startminimized = '1'
59 | self._fajradhan = (self.get_fajr_adhans())[0]
60 | self._normaladhan = (self.get_normal_adhans())[0]
61 | self._audionotifications = '1'
62 | self._daylightsavingtime = '1'
63 | self._hijricaladjustment = '0'
64 | self._language = 'English'
65 | self.save_options()
66 |
67 | except ValueError:
68 | print ("DEBUG: Problem while reading setting file, using the default settings")
69 | os.system("rm ~/.silaty")
70 | self._city = 'Makkah'
71 | self._country = 'Saudi Arabia'
72 | self._latitude = '21.25'
73 | self._longitude = '39.49'
74 | self._timezone = '3'
75 | self._calcmethodname = 'Makkah'
76 | self._madhab = 'Default'
77 | self._clockformat = '24h'
78 | self._notif = '10'
79 | self._iconlabel = '1'
80 | self._startminimized = '1'
81 | self._fajradhan = (self.get_fajr_adhans())[0]
82 | self._normaladhan = (self.get_normal_adhans())[0]
83 | self._audionotifications = '1'
84 | self._daylightsavingtime = '1'
85 | self._hijricaladjustment = '0'
86 | self._language = 'English'
87 | self.save_options()
88 |
89 | ## Functions with lists for the Buttons
90 | def get_cal_methods(self):
91 | return ['Makkah', 'Egypt', 'Karachi', 'ISNA', 'MWL']
92 |
93 | def get_madhahed(self):
94 | return ['Hanafi', 'Default']
95 |
96 | def get_clock_formats(self):
97 | return ['12h', '24h']
98 |
99 | def get_languages(self):
100 | return list(languages)
101 |
102 | def get_fajr_adhans(self):
103 | dirfiles = os.listdir(os.path.dirname(os.path.realpath(__file__)) + "/audio/Fajr/")
104 | wavfiles = filter(lambda song: song.endswith(".ogg"), dirfiles)
105 | adhans = list(map(lambda x: os.path.splitext(x)[0], wavfiles))
106 | return adhans
107 |
108 | def get_normal_adhans(self):
109 | dirfiles = os.listdir(os.path.dirname(os.path.realpath(__file__)) + "/audio/Normal/")
110 | wavfiles = filter(lambda song: song.endswith(".ogg"), dirfiles)
111 | adhans = list(map(lambda x: os.path.splitext(x)[0], wavfiles))
112 | return adhans
113 |
114 | ## Functions to get and set settings
115 | @property
116 | def audio_notifications_num(self):
117 | return self._audionotifications
118 |
119 | @audio_notifications_num.setter
120 | def audio_notifications_num(self, value):
121 | self._audionotifications = value
122 |
123 | @property
124 | def audio_notifications(self):
125 | #print ("DEBUG: getting audio notifications settings @", (str(datetime.datetime.now())))
126 | if self.audio_notifications_num == '1':
127 | return True
128 | else:
129 | return False
130 |
131 | @audio_notifications.setter
132 | def audio_notifications(self, data):
133 | #print ("DEBUG: setting audio notifications settings @", (str(datetime.datetime.now())))
134 | if data == True:
135 | self.audio_notifications_num = '1'
136 | else:
137 | self.audio_notifications_num = '0'
138 |
139 | @property
140 | def fajr_adhan(self):
141 | return self._fajradhan
142 |
143 | @fajr_adhan.setter
144 | def fajr_adhan(self, value):
145 | self._fajradhan = value
146 |
147 | @property
148 | def normal_adhan(self):
149 | return self._normaladhan
150 |
151 | @normal_adhan.setter
152 | def normal_adhan(self, value):
153 | self._normaladhan = value
154 |
155 | @property
156 | def city(self):
157 | #print ("DEBUG: getting city settings @", (str(datetime.datetime.now())))
158 | return self._city
159 |
160 | @city.setter
161 | def city(self, data):
162 | #print ("DEBUG: setting city settings @", (str(datetime.datetime.now())))
163 | self._city = data
164 |
165 | @property
166 | def country(self):
167 | #print ("DEBUG: getting country settings @", (str(datetime.datetime.now())))
168 | return self._country
169 | @country.setter
170 | def country(self, value):
171 | #print ("DEBUG: setting country settings @", (str(datetime.datetime.now())))
172 | self._country = value
173 |
174 | @property
175 | def calculation_method_name(self):
176 | return self._calcmethodname
177 |
178 | @calculation_method_name.setter
179 | def calculation_method_name(self, value):
180 | self._calcmethodname = value
181 |
182 | @property
183 | def calculation_method(self):
184 | #print ("DEBUG: getting calculation method settings @", (str(datetime.datetime.now())))
185 | if self.calculation_method_name == 'Makkah':
186 | return Calendar.UmmAlQuraUniv
187 | elif self.calculation_method_name == 'Egypt':
188 | return Calendar.EgyptianGeneralAuthorityOfSurvey
189 | elif self.calculation_method_name == 'Karachi':
190 | return Calendar.UnivOfIslamicSciencesKarachi
191 | elif self.calculation_method_name == 'ISNA':
192 | return Calendar.IslamicSocietyOfNorthAmerica
193 | elif self.calculation_method_name == 'MWL':
194 | return Calendar.MuslimWorldLeague
195 |
196 | @calculation_method.setter
197 | def calculation_method(self, data):
198 | #print ("DEBUG: setting calculation method settings @", (str(datetime.datetime.now())))
199 | self.calculation_method_name = data
200 |
201 | @property
202 | def madhab_name(self):
203 | return self._madhab
204 |
205 | @madhab_name.setter
206 | def madhab_name(self, value):
207 | self._madhab = value
208 |
209 | @property
210 | def madhab(self):
211 | #print ("DEBUG: getting madhab settings @", (str(datetime.datetime.now())))
212 | if self.madhab_name == 'Default':
213 | return Madhab.Default
214 | if self.madhab_name == 'Hanafi':
215 | return Madhab.Hanafi
216 |
217 | @madhab.setter
218 | def madhab(self, data):
219 | #print ("DEBUG: setting madhab settings @", (str(datetime.datetime.now())))
220 | self._madhab = data
221 |
222 | @property
223 | def latitude(self):
224 | #print ("DEBUG: getting latitude settings @", (str(datetime.datetime.now())))
225 | return float(self._latitude)
226 |
227 | @latitude.setter
228 | def latitude(self, data):
229 | #print ("DEBUG: setting latitude settings @", (str(datetime.datetime.now())))
230 | self._latitude = str(data)
231 |
232 | @property
233 | def longitude(self):
234 | #print ("DEBUG: getting longitude settings @", (str(datetime.datetime.now())))
235 | return float(self._longitude)
236 |
237 | @longitude.setter
238 | def longitude(self, data):
239 | #print ("DEBUG: setting longitude settings @", (str(datetime.datetime.now())))
240 | self._longitude = str(data)
241 |
242 | @property
243 | def timezone(self):
244 | #print ("DEBUG: getting timezone settings @", (str(datetime.datetime.now())))
245 | return float(self._timezone)
246 |
247 | @timezone.setter
248 | def timezone(self, data):
249 | #print ("DEBUG: setting timezone settings @", (str(datetime.datetime.now())))
250 | self._timezone = str(data)
251 |
252 | @property
253 | def notification_time(self):
254 | #print ("DEBUG: getting notification time settings @", (str(datetime.datetime.now())))
255 | return float(self._notif)
256 |
257 | @notification_time.setter
258 | def notification_time(self, data):
259 | #print ("DEBUG: setting notification time settings @", (str(datetime.datetime.now())))
260 | self._notif = str(data)
261 |
262 | @property
263 | def hijrical_adjustment(self):
264 | #print ("DEBUG: getting hijri cal adjustment settings @", (str(datetime.datetime.now())))
265 | return float(self._hijricaladjustment)
266 |
267 | @hijrical_adjustment.setter
268 | def hijrical_adjustment(self, data):
269 | #print ("DEBUG: setting hijri cal adjustment settings @", (str(datetime.datetime.now())))
270 | self._hijricaladjustment = str(data)
271 |
272 | @property
273 | def language(self):
274 | return self._language
275 |
276 | @language.setter
277 | def language(self, value):
278 | self._language = value
279 |
280 | @property
281 | def iconlabel_num(self):
282 | return self._iconlabel
283 |
284 | @iconlabel_num.setter
285 | def iconlabel_num(self, value):
286 | self._iconlabel = value
287 |
288 | @property
289 | def iconlabel(self):
290 | #print ("DEBUG: getting icon label settings @", (str(datetime.datetime.now())))
291 | if self.iconlabel_num == '1':
292 | return True
293 | else:
294 | return False
295 |
296 | @iconlabel.setter
297 | def iconlabel(self, data):
298 | #print ("DEBUG: setting icon label settings @", (str(datetime.datetime.now())))
299 | if data == True:
300 | self.iconlabel_num = '1'
301 | else:
302 | self.iconlabel_num = '0'
303 |
304 | @property
305 | def start_minimized_num(self):
306 | return self._startminimized
307 |
308 | @start_minimized_num.setter
309 | def start_minimized_num(self, value):
310 | self._startminimized = value
311 |
312 | @property
313 | def start_minimized(self):
314 | #print ("DEBUG: getting start minimized settings @", (str(datetime.datetime.now())))
315 | if self.start_minimized_num == '1':
316 | return True
317 | else:
318 | return False
319 |
320 | @start_minimized.setter
321 | def start_minimized(self, data):
322 | #print ("DEBUG: setting start minimized settings @", (str(datetime.datetime.now())))
323 | if data == True:
324 | self.start_minimized_num = '1'
325 | else:
326 | self.start_minimized_num = '0'
327 |
328 | @property
329 | def daylight_saving_time_num(self):
330 | return self._daylightsavingtime
331 |
332 | @daylight_saving_time_num.setter
333 | def daylight_saving_time_num(self, value):
334 | self._daylightsavingtime = value
335 |
336 | @property
337 | def daylight_saving_time(self):
338 | #print ("DEBUG: getting daylight saving time settings @", (str(datetime.datetime.now())))
339 | if self.daylight_saving_time_num == '1':
340 | return True
341 | else:
342 | return False
343 |
344 | @daylight_saving_time.setter
345 | def daylight_saving_time(self, data):
346 | #print ("DEBUG: setting daylight saving time settings @", (str(datetime.datetime.now())))
347 | if data == True:
348 | self.daylight_saving_time_num = '1'
349 | else:
350 | self.daylight_saving_time_num = '0'
351 |
352 | @property
353 | def clock_format(self):
354 | #print ("DEBUG: getting clock format settings @", (str(datetime.datetime.now())))
355 | return self._clockformat
356 |
357 | @clock_format.setter
358 | def clock_format(self, data):
359 | #print ("DEBUG: setting clock format settings @", (str(datetime.datetime.now())))
360 | self._clockformat = data
361 |
362 | ## Function to save the options
363 | def save_options(self):
364 | print ("DEBUG: saving settings file @", (str(datetime.datetime.now())))
365 | config = open(os.path.expanduser('~/.silaty'), 'w')
366 | Text='''# Silaty Settings File
367 |
368 | [DEFAULT]
369 | # Location Information
370 | city = %s
371 | country = %s
372 | latitude = %s
373 | longitude = %s
374 | timezone = %s
375 | language = %s
376 |
377 | # Possible Values for Calculation Methods
378 | # Makkah
379 | # Egypt
380 | # Karachi
381 | # ISNA
382 | # MWL
383 | calculation-method = %s
384 |
385 | # Possible Values for Madhaheb
386 | # Default
387 | # Hanafi
388 | madhab = %s
389 |
390 | # Possible Values for Clock Format
391 | # 24h
392 | # 12h
393 | clock-format = %s
394 |
395 | # Time before prayer for notification
396 | notif = %s
397 |
398 | # Display Time by the indicator icon
399 | iconlabel = %s
400 |
401 | # Should audio notifications be enabled
402 | audio-notifications = %s
403 |
404 | # Should the application start minimized
405 | minimized = %s
406 |
407 | # Should the application use daylight saving time
408 | daylight-saving-time = %s
409 |
410 | # Adjust Hijri Calendar
411 | hijrical-adjustment = %s
412 |
413 | # Paths to the audio files
414 | fajr-adhan = %s
415 | normal-adhan = %s
416 |
417 | ''' % (self.city, self.country, self.latitude, self.longitude, self.timezone, self.language, \
418 | self.calculation_method_name, self.madhab_name, self.clock_format, \
419 | self.notification_time, self.iconlabel_num, self.audio_notifications_num, self.start_minimized_num, \
420 | self.daylight_saving_time_num, self.hijrical_adjustment, self.fajr_adhan, self.normal_adhan)
421 | config.write(Text)
422 | config.close()
423 |
--------------------------------------------------------------------------------
/prayertime.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | #
4 | # prayertime.py
5 | #
6 | # Copyright 2010 ahmed youssef
7 | # Copyright 2014 Jesse Brandao
8 | # Copyright 2019 AXeL-dev
9 | #
10 | # This program is free software you can redistribute it and/or modify
11 | # it under the terms of the GNU General Public License as published by
12 | # the Free Software Foundation either version 2 of the License, or
13 | # (at your option) any later version.
14 | #
15 | # This program is distributed in the hope that it will be useful,
16 | # but WITHOUT ANY WARRANTY without even the implied warranty of
17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | # GNU General Public License for more details.
19 | #
20 | # You should have received a copy of the GNU General Public License
21 | # along with this program if not, write to the Free Software
22 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | # MA 02110-1301, USA.
24 |
25 | __author__ = "Jesse Wayde Brandão (Abdul Hakim)"
26 | __all__ = ['Calendar', 'Prayertime', 'Madhab', 'as_pytime', 'as_pydatetime']
27 |
28 | import gi
29 | gi.require_version('Gtk', '3.0')
30 | gi.require_version('Notify', '0.7')
31 | from gi.repository import Gtk, Gst, GObject, Gio, GLib, GdkPixbuf, Notify
32 | from math import degrees, radians, atan, atan2, asin, acos, cos, sin, tan, fabs
33 | from datetime import date, timedelta
34 | from time import strptime
35 | from options import *
36 | from translate import translate_text as _
37 | import datetime
38 | import time
39 | import os
40 | import subprocess
41 |
42 | class Prayertime(object):
43 |
44 | def __init__(self):
45 | GLib.threads_init()
46 | Gst.init(None)
47 |
48 | self.options = Options()
49 |
50 | year = datetime.datetime.now().year
51 | month = datetime.datetime.now().month
52 | day = datetime.datetime.now().day
53 | self.date = date(year, month, day)
54 |
55 | self._shrouk = None
56 | self._fajr = None
57 | self._zuhr = None
58 | self._asr = None
59 | self._maghrib = None
60 | self._isha = None
61 | self._nextprayer = ""
62 | self._tnprayer = 0
63 | self.dec = 0
64 |
65 | def shrouk_time(self):
66 | """Gets the time of shrouk."""
67 | fmt = to_hrtime(self._shrouk, True)
68 | if "00" in fmt:
69 | fmt = fmt.replace('00','12')
70 | return fmt
71 |
72 | def fajr_time(self):
73 | """Gets the time of fajr."""
74 | fmt = to_hrtime(self._fajr, True)
75 | if "00" in fmt:
76 | fmt = fmt.replace('00','12')
77 | return fmt
78 |
79 | def zuhr_time(self):
80 | """Gets the time of zuhr."""
81 | fmt = to_hrtime(self._zuhr, True)
82 | if "00" in fmt:
83 | fmt = fmt.replace('00','12')
84 | return fmt
85 |
86 | def asr_time(self):
87 | """Gets the time of asr."""
88 | fmt = to_hrtime(self._asr)
89 | if "00" in fmt:
90 | fmt = fmt.replace('00','12')
91 | return fmt
92 |
93 | def maghrib_time(self):
94 | """Gets the time of maghrib"""
95 | fmt = to_hrtime(self._maghrib)
96 | if "00" in fmt:
97 | fmt = fmt.replace('00','12')
98 | return fmt
99 |
100 | def isha_time(self):
101 | """Gets the time of isha"""
102 | fmt = to_hrtime(self._isha)
103 | if "00" in fmt:
104 | fmt = fmt.replace('00','12')
105 | return fmt
106 |
107 | def next_prayer(self):
108 | return self._nextprayer
109 |
110 | def time_to_next_prayer(self):
111 | return self._tnprayer
112 |
113 | def calculate(self, notify_also = True):
114 | """Calculations of prayertimes."""
115 | year = self.date.year
116 | month = self.date.month
117 | day = self.date.day
118 | longitude = self.options.longitude
119 | latitude = self.options.latitude
120 | zone = self.options.timezone
121 | julian_day = (367*year)-int(((year+int((month+9)/12))*7)/4)+int(275*month/9)+day-730531.5
122 | sun_length = (280.461+0.9856474*julian_day)%360
123 | middle_sun = (357.528+0.9856003*julian_day)%360
124 |
125 | lamda = (sun_length+1.915*sin(radians(middle_sun))+0.02*sin(radians(2*middle_sun)))%360
126 |
127 | obliquity = 23.439-0.0000004*julian_day
128 |
129 | alpha = degrees(atan(cos(radians(obliquity))*tan(radians(lamda))))
130 |
131 | if 90 < lamda < 180:
132 | alpha += 180
133 | elif 179 < lamda < 360:
134 | alpha += 360
135 |
136 | ST = (100.46+0.985647352*julian_day)%360
137 |
138 | self.dec = degrees(asin(sin(radians(obliquity))*sin(radians(lamda))))
139 |
140 | noon = alpha-ST
141 |
142 | if noon < 0:
143 | noon += 360
144 |
145 | UTNoon = noon-longitude
146 | zuhr = (UTNoon/15)+zone # Zuhr Time.
147 | maghrib = zuhr+self._equation(-0.8333)/15 # Maghrib Time
148 | shrouk = zuhr-self._equation(-0.8333)/15 # Shrouk Time
149 |
150 | fajr_alt = 0
151 | isha_alt = 0
152 |
153 | if self.options.calculation_method == Calendar.UmmAlQuraUniv:
154 | fajr_alt = -19
155 | elif self.options.calculation_method == Calendar.EgyptianGeneralAuthorityOfSurvey:
156 | fajr_alt = -19.5
157 | isha_alt = -17.5
158 | elif self.options.calculation_method == Calendar.MuslimWorldLeague:
159 | fajr_alt = -18
160 | isha_alt = -17
161 | elif self.options.calculation_method == Calendar.IslamicSocietyOfNorthAmerica:
162 | fajr_alt = isha_alt = -15
163 | elif self.options.calculation_method == Calendar.UnivOfIslamicSciencesKarachi:
164 | fajr_alt = isha_alt = -18
165 |
166 | fajr = zuhr-self._equation(fajr_alt)/15 # Fajr Time
167 | isha = zuhr+self._equation(isha_alt)/15 # Isha Time
168 |
169 | if self.options.calculation_method == Calendar.UmmAlQuraUniv :
170 | isha = maghrib+1.5
171 |
172 | asr_alt = 0
173 |
174 | if self.options.madhab == Madhab.Hanafi :
175 | asr_alt = 90 - degrees(atan(2+tan(radians(abs(latitude - self.dec)))))
176 | else:
177 | asr_alt = 90 - degrees(atan(1 + tan(radians(abs(latitude - self.dec)))))
178 |
179 | asr = zuhr+self._equation(asr_alt)/15 # Asr Time.
180 |
181 | # Add one hour to all times if the season is Summmer.
182 | if self.options.daylight_saving_time and is_dst() :
183 | fajr += 1
184 | shrouk += 1
185 | zuhr += 1
186 | asr += 1
187 | maghrib += 1
188 | isha += 1
189 |
190 | self._shrouk = shrouk
191 | self._fajr = fajr
192 | self._zuhr = zuhr
193 | self._asr = asr
194 | self._maghrib = maghrib
195 | self._isha = isha
196 |
197 | # Transform Times To DateTimes ,so We Can Make Calculations on it
198 | Fajr = datetime.datetime.strptime(self.fajr_time(),"%I:%M:%S %p")
199 | Dhuhr = datetime.datetime.strptime(self.zuhr_time(),"%I:%M:%S %p")
200 | Asr = datetime.datetime.strptime(self.asr_time(),"%I:%M:%S %p")
201 | Maghrib = datetime.datetime.strptime(self.maghrib_time(),"%I:%M:%S %p")
202 | Isha = datetime.datetime.strptime(self.isha_time(),"%I:%M:%S %p")
203 |
204 | # Assign Times to A List
205 | PrayerTimes = [Fajr, Dhuhr, Asr, Maghrib, Isha]
206 | Time = datetime.datetime.now()# Time Now
207 | Time = Time.replace(microsecond=0, year=1900, month=1, day=1)# Replace year,month and day to be the same on PrayerTimes
208 |
209 | NotifTime = Time+datetime.timedelta(minutes=self.options.notification_time)# Ten Minutes Before Next Prayer
210 | ClosestPrayer = self.closest(Time, PrayerTimes)# Get The Closest Prayer Time
211 | PrayerIndex = PrayerTimes.index(ClosestPrayer)# Get Index From List
212 |
213 | if PrayerIndex == 0:
214 | CurrentPrayer='Fajr'
215 | if Time < Fajr:
216 | PrevPrayer = 'Isha'
217 | NextPrayer = 'Fajr'
218 | NextPrayerDT = Fajr
219 | else:
220 | PrevPrayer = 'Fajr'
221 | NextPrayer = 'Dhuhr'
222 | NextPrayerDT = Dhuhr
223 |
224 | if PrayerIndex == 1:
225 | CurrentPrayer = 'Dhuhr'
226 | if Time < Dhuhr:
227 | PrevPrayer = 'Fajr'
228 | NextPrayer = 'Dhuhr'
229 | NextPrayerDT = Dhuhr
230 | else:
231 | PrevPrayer = 'Dhuhr'
232 | NextPrayer = 'Asr'
233 | NextPrayerDT = Asr
234 |
235 | elif PrayerIndex == 2:
236 | CurrentPrayer = 'Asr'
237 | if Time < Asr:
238 | PrevPrayer = 'Dhuhr'
239 | NextPrayer = 'Asr'
240 | NextPrayerDT = Asr
241 | else:
242 | PrevPrayer = 'Asr'
243 | NextPrayer = 'Maghrib'
244 | NextPrayerDT = Maghrib
245 |
246 | elif PrayerIndex == 3:
247 | CurrentPrayer = 'Maghrib'
248 | if Time < Maghrib:
249 | PrevPrayer = 'Asr'
250 | NextPrayer = 'Maghrib'
251 | NextPrayerDT = Maghrib
252 | else:
253 | PrevPrayer = 'Maghrib'
254 | NextPrayer = 'Isha'
255 | NextPrayerDT = Isha
256 |
257 | elif PrayerIndex == 4:
258 | CurrentPrayer = 'Isha'
259 | if Time < Isha:
260 | PrevPrayer = 'Maghrib'
261 | NextPrayer = 'Isha'
262 | NextPrayerDT = Isha
263 | else:
264 | PrevPrayer = 'Isha'
265 | NextPrayer = 'Fajr'
266 | NextPrayerDT = Fajr
267 |
268 | # Calculate Time to The Next Prayer
269 | TimeToNextPrayer = NextPrayerDT-Time
270 | if TimeToNextPrayer.total_seconds() < 0:
271 | # Add a day to fix the timining
272 | TimeToNextPrayer = TimeToNextPrayer + timedelta(days=1)
273 |
274 | self._nextprayer = NextPrayer
275 | self._tnprayer = TimeToNextPrayer
276 |
277 | # Notification
278 | if notify_also:
279 | for time in PrayerTimes:
280 | if time == NotifTime:
281 | self.notify(_('Get Ready'), _('%s minutes left until the %s prayer.') % (str(int(self.options.notification_time)), _(NextPrayer)))
282 | elif time == Time:
283 | self.notify(_('Prayer time for %s') % _(CurrentPrayer), _("It's time for the %s prayer.") % _(CurrentPrayer), self.options.audio_notifications, CurrentPrayer)
284 |
285 | def muteApps(self, value = 'true'):
286 | try:
287 | inputs = subprocess.getoutput('pacmd list-sink-inputs | sed -n "s/^\\s*index: \\([[:digit:]]*\\)/\\1/p"').split('\n')
288 | clients = subprocess.getoutput('pacmd list-sink-inputs | sed -n "s/^\\s*client: [[:digit:]]* <\\(.*\\)>/\\1/p"').split('\n')
289 | for i in range(len(inputs)):
290 | if clients[i] not in ['silaty-indicator', 'ZOOM VoiceEngine']:
291 | subprocess.Popen(['pacmd', 'set-sink-input-mute', inputs[i], value])
292 | except:
293 | print ("DEBUG: Cannot mute apps @", (str(datetime.datetime.now())))
294 |
295 | def notify(self, title, message, play_audio = False, current_prayer = ''):
296 | Notify.init("Silaty")
297 | notif = Notify.Notification.new(title, message)
298 | icon = GdkPixbuf.Pixbuf.new_from_file(os.path.dirname(os.path.realpath(__file__)) + "/icons/hicolor/128x128/apps/silaty.svg")
299 | notif.set_icon_from_pixbuf(icon)
300 |
301 | if play_audio:
302 | self.muteApps()
303 | if current_prayer == 'Fajr':
304 | uri = "file://" + os.path.dirname(os.path.realpath(__file__)) + "/audio/Fajr/" + self.options.fajr_adhan + ".ogg"
305 | self.fajrplayer = Gst.ElementFactory.make("playbin", "player")
306 | fakesink = Gst.ElementFactory.make("fakesink", "fakesink")
307 | self.fajrplayer.set_property('uri', uri)
308 | self.fajrplayer.set_property("video-sink", fakesink)
309 | self.fajrplayer.set_state(Gst.State.PLAYING)
310 | bus = self.fajrplayer.get_bus()
311 | bus.add_signal_watch()
312 | bus.connect("message", self.on_fajrplayer_message)
313 | else:
314 | uri = "file://" + os.path.dirname(os.path.realpath(__file__)) + "/audio/Normal/" + self.options.normal_adhan + ".ogg"
315 | self.normalplayer = Gst.ElementFactory.make("playbin", "player")
316 | fakesink = Gst.ElementFactory.make("fakesink", "fakesink")
317 | self.normalplayer.set_property('uri', uri)
318 | self.normalplayer.set_property("video-sink", fakesink)
319 | self.normalplayer.set_state(Gst.State.PLAYING)
320 | bus = self.normalplayer.get_bus()
321 | bus.add_signal_watch()
322 | bus.connect("message", self.on_normalplayer_message)
323 |
324 | notif.set_app_name('Silaty')
325 | notif.show()
326 |
327 | def on_fajrplayer_message(self, bus, message):
328 | t = message.type
329 | if t == Gst.MessageType.EOS: # track is finished
330 | self.fajrplayer.set_state(Gst.State.NULL)
331 | self.muteApps('false')
332 | elif t == Gst.MessageType.ERROR:
333 | self.fajrplayer.set_state(Gst.State.NULL)
334 | self.muteApps('false')
335 | err, debug = message.parse_error()
336 | print ("Error: %s" % err, debug)
337 |
338 | def on_normalplayer_message(self, bus, message):
339 | t = message.type
340 | if t == Gst.MessageType.EOS: # track is finished
341 | self.normalplayer.set_state(Gst.State.NULL)
342 | self.muteApps('false')
343 | elif t == Gst.MessageType.ERROR:
344 | self.normalplayer.set_state(Gst.State.NULL)
345 | self.muteApps('false')
346 | err, debug = message.parse_error()
347 | print ("Error: %s" % err, debug)
348 |
349 | def closest(self, target, collection) :# Returns the closest Adhan
350 | return min((abs(target - i), i) for i in collection)[1]
351 |
352 | def _equation(self, alt):
353 | return degrees( acos( (sin(radians(alt)) - sin(radians(self.dec)) * sin(radians(self.options.latitude)))/(cos(radians(self.dec))*cos(radians(self.options.latitude)))))
354 |
355 | def report(self):
356 | """Simple report of all prayertimes."""
357 | print ('Fajr Time is %s' % self.fajr_time())
358 | print ('Shrouk Time is %s' % self.shrouk_time())
359 | print ('Zuhr Time is %s' % self.zuhr_time())
360 | print ('Asr Time is %s' % self.asr_time())
361 | print ('Maghrib Time is %s' % self.maghrib_time())
362 | print ('Ishaa Time is %s' % self.isha_time())
363 |
364 | def get_qibla(self):
365 | k_lat = radians(21.423333);
366 | k_lon = radians(39.823333);
367 |
368 | longitude = radians(self.options.longitude)
369 | latitude = radians(self.options.latitude)
370 |
371 | numerator = sin(k_lon - longitude)
372 | denominator = (cos(latitude) * tan(k_lat)) - (sin(latitude) * cos(k_lon - longitude))
373 |
374 | q = atan2(numerator,denominator)
375 | q = degrees(q)
376 | if q < 0 : q += 360
377 |
378 | return q
379 |
380 | def qibla_distance(self):
381 | k_lat = radians(21.423333);
382 | k_lon = radians(39.823333);
383 |
384 | longitude = radians(self.options.longitude)
385 | latitude = radians(self.options.latitude)
386 |
387 | r = 6378.7 # kilometers
388 |
389 | return acos(sin(k_lat) * sin(latitude) + cos(k_lat) * cos(latitude) * cos(longitude-k_lon)) * r
390 |
391 | if __name__=="__main__":
392 | pt = Prayertime()
393 | print ("%s" % pt.get_qibla())
394 | print ("%s" % pt.qibla_distance())
395 | pt.calculate()
396 | pt.report()
397 |
398 | def is_dst():
399 | # Find out whether or not daylight savings is in effect
400 | return bool(time.localtime().tm_isdst)
401 |
402 | def fill_zeros(time):
403 | fill = lambda var: [var, '0'+var] [len(var) <2]
404 | return ':'.join(map(fill, time.split(':')))
405 |
406 | def to_hrtime(var, isAM=False):
407 | """var: double -> human readable string of format "%I:%M:%S %p" """
408 | time = ''
409 | hours = int(var) # cast var (initially a double) as an int
410 | hours_mod = hours % 12
411 |
412 | # Check if time correspond to morning or afternoon
413 | #print ('%s %s' % (hours, hours_mod))
414 | if isAM:
415 | if hours_mod > 1 and hours_mod < 12:
416 | zone = "AM"
417 | else:
418 | zone = "PM"
419 | else:
420 | zone = "PM"
421 |
422 | # This will give us the time from 0 to 12
423 | if hours > 12:
424 | time += str(hours_mod)
425 | else:
426 | time += str(hours)
427 | time += ":"
428 | var -= hours
429 |
430 | # Get the minutes from the left over time
431 | minutes = int(var*60)
432 | time += str(abs(minutes))
433 | time += ":"
434 | var -= minutes/100
435 |
436 | # And get the seconds from what's left over of that
437 | sec = int(fabs(60*var))
438 |
439 | time += str(sec)
440 | time = fill_zeros(time)
441 | time += " "
442 |
443 | # Add the AM or PM
444 | time += zone
445 |
446 | #print ('%s' % time)
447 | return time
448 |
449 | def as_pytime(string_to_parse, fmt="%I:%M:%SS %p"):
450 | """returns time.tm_struct by parsing string_to_parse."""
451 | return strptime(string_to_parse, fmt)
452 |
453 | def as_pydatetime(d, ts):
454 | """returns a datetime object.
455 | d: date object
456 | ts: tm_struct
457 | """
458 | return datetime(year=d.year, month=d.month, day=d.day, \
459 | hour=ts.tm_hour, minute=ts.tm_min, second=ts.tm_sec)
460 |
--------------------------------------------------------------------------------
/qiblacompass.py:
--------------------------------------------------------------------------------
1 | # Silaty
2 | # Copyright (c) 2018 - 2021 AXeL
3 | # Copyright (c) 2014 - 2015 Jessewb786
4 |
5 | import gi
6 | gi.require_version('Gtk', '3.0')
7 | from gi.repository import Gtk, GLib, Gio, Gdk, GdkPixbuf
8 | from translate import translate_text as _
9 |
10 | class QiblaCompass(Gtk.Box):
11 | def __init__(self, qibladirection, country, city):
12 | Gtk.Box.__init__(self)
13 |
14 | self.mainbox = Gtk.Box()
15 | self.mainbox.set_orientation(Gtk.Orientation.VERTICAL)
16 |
17 | qibla = self.set_compass(qibladirection)
18 | qibla.props.valign = Gtk.Align.START
19 |
20 | ## Make the top label
21 | qiblatitle = Gtk.Label(label=_("Qibla direction :"), margin_left=20, margin_right=20)
22 | qiblatitle.props.halign = Gtk.Align.START
23 | self.mainbox.pack_start(qiblatitle, False, False, 12)
24 |
25 | ## Set the compass image
26 | self.mainbox.pack_start(qibla, False, True, 0)
27 |
28 | ## Set the country and city
29 | vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,spacing=6)
30 | qiblalabel = Gtk.Label(label=_("Country : %s") % country)
31 | qiblalabel.props.halign = Gtk.Align.CENTER
32 | qiblalabel.props.valign = Gtk.Align.CENTER
33 | vbox.pack_start(qiblalabel, True,True, 0)
34 |
35 | qiblalabel = Gtk.Label(label=_("City : %s") % city)
36 | qiblalabel.props.halign = Gtk.Align.CENTER
37 | qiblalabel.props.valign = Gtk.Align.CENTER
38 | vbox.pack_start(qiblalabel, True, True, 0)
39 |
40 | ## Add it all in the end
41 | self.mainbox.pack_start(vbox, False, False, 12)
42 | self.pack_start(self.mainbox, True, True, 0)
43 |
44 | def set_compass(self, qibladirection):
45 | print ("DEBUG: Showing Qibla window")
46 | img='''
47 | ''' % (qibladirection-90, qibladirection)
70 | stream = Gio.MemoryInputStream.new_from_bytes(GLib.Bytes.new(img.encode('utf-8')))
71 | pixbuf = GdkPixbuf.Pixbuf.new_from_stream(stream, None)
72 | svgwidget = Gtk.Image.new_from_pixbuf(pixbuf)
73 | return svgwidget
74 |
75 | def update_compass(self, qibladirection, country, city):
76 | ## The only way to update so far is to remove the whole thing and create it again
77 | self.remove(self.mainbox)
78 |
79 | self.mainbox = Gtk.Box()
80 | self.mainbox.set_orientation(Gtk.Orientation.VERTICAL)
81 |
82 | qibla = self.set_compass(qibladirection)
83 | qibla.props.valign = Gtk.Align.START
84 |
85 | ## Make the top label
86 | qiblatitle = Gtk.Label(label=_("Qibla direction :"), margin_left=20, margin_right=20)
87 | qiblatitle.props.halign = Gtk.Align.START
88 | self.mainbox.pack_start(qiblatitle, False, False, 12)
89 |
90 | ## Set the compass image
91 | self.mainbox.pack_start(qibla, False, True, 0)
92 |
93 | ## Set the country and city
94 | vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,spacing=6)
95 | qiblalabel = Gtk.Label(label=_("Country : %s") % country)
96 | qiblalabel.props.halign = Gtk.Align.CENTER
97 | qiblalabel.props.valign = Gtk.Align.CENTER
98 | vbox.pack_start(qiblalabel, True,True, 0)
99 |
100 | qiblalabel = Gtk.Label(label=_("City : %s") % city)
101 | qiblalabel.props.halign = Gtk.Align.CENTER
102 | qiblalabel.props.valign = Gtk.Align.CENTER
103 | vbox.pack_start(qiblalabel, True, True, 0)
104 |
105 | ## Add it all in the end
106 | self.mainbox.pack_start(vbox, False, False, 12)
107 | self.pack_start(self.mainbox, True, True, 0)
108 | self.show_all()
--------------------------------------------------------------------------------
/screenshots/Silaty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/screenshots/Silaty.png
--------------------------------------------------------------------------------
/screenshots/Silaty_calendar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/screenshots/Silaty_calendar.png
--------------------------------------------------------------------------------
/screenshots/Silaty_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/screenshots/Silaty_notification.png
--------------------------------------------------------------------------------
/screenshots/Silaty_qibla.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/screenshots/Silaty_qibla.png
--------------------------------------------------------------------------------
/screenshots/Silaty_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/screenshots/Silaty_settings.png
--------------------------------------------------------------------------------
/screenshots/linux-download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/screenshots/linux-download.png
--------------------------------------------------------------------------------
/screenshots/windows-download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxForGeeks/Silaty/4b0a851b9a931ab14caa4311a0512aa322bf06f0/screenshots/windows-download.png
--------------------------------------------------------------------------------
/settingspane.py:
--------------------------------------------------------------------------------
1 | # Silaty
2 | # Copyright (c) 2018 - 2021 AXeL
3 | # Copyright (c) 2014 - 2015 Jessewb786
4 |
5 | import gi
6 | gi.require_version('Gtk', '3.0')
7 | from gi.repository import Gtk
8 |
9 | class SettingsPane(Gtk.Box):
10 | def __init__(self):
11 | Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL, margin_top=12, margin_bottom=6, margin_left=12, margin_right=12)
12 | self.nrows = 0
13 | self.ngrids = -1
14 | self.grids = []
15 |
16 | def add_grid(self):
17 | grid = Gtk.Grid(column_spacing=3, row_spacing=6, margin_right=12, margin_left=12, margin_top=6, margin_bottom=6)
18 | #grid.set_row_homogeneous(True)
19 | grid.set_column_homogeneous(True)
20 | grid.set_halign(Gtk.Align.FILL)
21 | grid.set_valign(Gtk.Align.START)
22 | self.pack_start(grid, True, True, 0)
23 | self.grids.append(grid)
24 |
25 | def add_setting(self, setting, label):
26 | label.set_halign(Gtk.Align.START)
27 | self.grids[self.ngrids].attach(label, 0, self.nrows, 1, 1)
28 | self.grids[self.ngrids].attach_next_to(setting, label, Gtk.PositionType.RIGHT, 1, 1)
29 | self.nrows += 1
30 |
31 | def add_category(self, category):
32 | label = Gtk.Label(label=""+category+"")
33 | label.set_use_markup(True)
34 | label.set_halign(Gtk.Align.START)
35 | self.pack_start(label, True, True, 0)
36 | self.add_grid()
37 | self.nrows = 0
38 | self.ngrids += 1
39 |
--------------------------------------------------------------------------------
/sidebar.py:
--------------------------------------------------------------------------------
1 | # Silaty
2 | # Copyright (c) 2018 - 2021 AXeL
3 | # Copyright (c) 2014 - 2015 Jessewb786
4 |
5 | import gi
6 | gi.require_version('Gtk', '3.0')
7 | from gi.repository import Gtk, Gdk, GLib, GdkPixbuf, GObject
8 |
9 | class SideBar(Gtk.Grid):
10 | def __init__(self, stack = Gtk.Stack()):
11 | Gtk.Grid.__init__(self)
12 | self.set_orientation(Gtk.Orientation.VERTICAL)
13 | color = 70.0/256.0
14 | self.override_background_color(Gtk.StateFlags.NORMAL, Gdk.RGBA.from_color(Gdk.Color.from_floats(color,color,color)))
15 | self._childlength = 0
16 | self.stackchildnames = []
17 | self.stack = stack
18 | self.connect("window-shown", self.activate_button)
19 |
20 | @property
21 | def childlength(self):
22 | return self._childlength
23 |
24 | @childlength.setter
25 | def childlength(self, value):
26 | self._childlength = value
27 |
28 | def new_button(self, inact_icon, act_icon, on_press_callback = None):
29 | sidebaricon = SideBarButton(inact_icon, act_icon, on_press_callback)
30 | self.attach(sidebaricon, 0, self.childlength, 1, 1)
31 |
32 | sidebaricon.position = self.childlength
33 | if on_press_callback is None:
34 | sidebaricon.connect("sidebar-button-pressed", self.change_visible_stack, sidebaricon.position)
35 |
36 | self.childlength += 1
37 |
38 | def add_to_stack(self, widget, name):
39 | self.stack.add_named(widget, name)
40 | self.stackchildnames.append(name)
41 |
42 | def change_visible_stack(self, widget, position):
43 | self.stack.set_visible_child_name(self.stackchildnames[position])
44 | self.emit("stack-changed", self.stackchildnames[position])
45 |
46 | def activate_button(self, widget):
47 | visiblechild = self.stack.get_visible_child_name()
48 | index = self.stackchildnames.index(visiblechild)
49 | self.get_child(index).state = SideBarButtonState.ON
50 | self.get_child(index).iconstack.set_visible_child_name('active')
51 | self.emit("stack-changed", visiblechild)
52 |
53 | def get_child(self, index):
54 | return self.get_child_at(0, index)
55 |
56 | class SideBarButton(Gtk.EventBox):
57 | def __init__(self, inactive_icon, active_icon, on_press_callback = None):
58 |
59 | Gtk.EventBox.__init__(self)
60 | self.set_events(Gdk.EventMask.BUTTON_PRESS_MASK)
61 | if on_press_callback is None:
62 | self.connect("button-press-event", self.on_icon_pressed)
63 | else:
64 | self.connect("button-press-event", on_press_callback)
65 |
66 | self.inactive_icon = inactive_icon
67 | self.active_icon = active_icon
68 | self._position = 0
69 | self._state = SideBarButtonState.OFF
70 |
71 | self.iconstack = Gtk.Stack(margin_left=12, margin_right=12, margin_top=6, margin_bottom=6)
72 | self.iconstack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
73 | self.iconstack.set_transition_duration(300)
74 |
75 | icon = self.set_image_from_file(self.inactive_icon)
76 | self.iconstack.add_named(icon, 'inactive')
77 |
78 | icon = self.set_image_from_file(self.active_icon)
79 | self.iconstack.add_named(icon, 'active')
80 |
81 | self.add(self.iconstack)
82 |
83 | @property
84 | def position(self):
85 | return self._position
86 |
87 | @position.setter
88 | def position(self, value):
89 | self._position = value
90 |
91 | @property
92 | def state(self):
93 | return self._state
94 |
95 | @state.setter
96 | def state(self, value):
97 | if value == SideBarButtonState.ON:
98 | self.iconstack.set_visible_child_name('active')
99 | else:
100 | self.iconstack.set_visible_child_name('inactive')
101 | self._state = value
102 |
103 | def on_icon_pressed(self, widget, data):
104 | parent = self.get_parent()
105 | for i in range(0, parent.childlength):
106 | if i == self.position:
107 | parent.get_child(i).state = SideBarButtonState.ON
108 | parent.get_child(i).emit("sidebar-button-pressed")
109 | else:
110 | parent.get_child(i).state = SideBarButtonState.OFF
111 |
112 | def set_image_from_file(self, iconpath):
113 | try:
114 | pixbuf = GdkPixbuf.Pixbuf.new_from_file(iconpath)
115 | icon = Gtk.Image.new_from_pixbuf(pixbuf)
116 | except GLib.GError:
117 | icon = Gtk.Image.new_from_stock(Gtk.STOCK_MISSING_IMAGE, Gtk.IconSize.LARGE_TOOLBAR)
118 | return icon
119 |
120 | class SideBarButtonState(object):
121 | ON, OFF = True, False
122 |
123 | GObject.type_register(SideBarButton)
124 | GObject.signal_new("sidebar-button-pressed", SideBarButton, GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, ())
125 |
126 | GObject.type_register(SideBar)
127 | GObject.signal_new("window-shown", SideBar, GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, ())
128 | GObject.signal_new("stack-changed", SideBar, GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, [GObject.TYPE_STRING])
--------------------------------------------------------------------------------
/silaty-indicator.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Silaty
5 | #
6 | # Copyright (c) 2018 - 2021 AXeL
7 | # Copyright (c) 2014 - 2015 Jessewb786
8 | #
9 | # TODO: Help document
10 | # TODO: Good Code Documentation
11 |
12 | import gi
13 | gi.require_version('Gtk', '3.0')
14 | gi.require_version('AppIndicator3', '0.1')
15 | from gi.repository import Gtk, GObject, Gio, GLib, Gdk, GdkPixbuf
16 | from gi.repository import AppIndicator3 as AI
17 | from datetime import date
18 | from hijrical import *
19 | from silaty import *
20 | from translate import translate_text as _
21 | import locale
22 | import sys
23 |
24 | # you might need to install the locale: sudo apt install language-pack-en
25 | locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
26 |
27 | class SilatyIndicator():
28 | def __init__(self):
29 | # Setup Indicator Applet
30 | self.Indicator = AI.Indicator.new("silaty-indicator", "silaty-indicator", AI.IndicatorCategory.APPLICATION_STATUS)
31 | self.Indicator.set_status(AI.IndicatorStatus.ACTIVE)
32 | self.Indicator.set_icon(self.icon())
33 |
34 | # Activate the Silaty Window
35 | self.silaty = Silaty(self)
36 |
37 | self.silaty.prayertimes.calculate()
38 | print ("DEBUG: Silaty started! @", (str(datetime.datetime.now())))
39 | print ("DEBUG: started prayer times report: @", (str(datetime.datetime.now())))
40 | self.silaty.prayertimes.report()
41 | print ("DEBUG: end of report @", (str(datetime.datetime.now())))
42 |
43 | # Setup the Menu
44 | print ("DEBUG: initialize the menu @", (str(datetime.datetime.now())))
45 | self.Menu = Gtk.Menu()
46 |
47 | # Add Hijri date
48 | print ("DEBUG: Adding hijri date to menu @", (str(datetime.datetime.now())))
49 | self.HijriDateItem = Gtk.MenuItem(self.get_hijri_date())
50 | self.HijriDateItem.connect("activate", self.show_home)
51 | self.Menu.append(self.HijriDateItem)
52 | self.Menu.append(Gtk.SeparatorMenuItem())
53 |
54 | # Add City
55 | print ("DEBUG: Adding city to menu @", (str(datetime.datetime.now())))
56 | self.CityItem = Gtk.MenuItem(_("Location: %s") % self.silaty.prayertimes.options.city, sensitive=False)
57 | self.Menu.append(self.CityItem)
58 |
59 | # Add Qibla Direction
60 | print ("DEBUG: Adding qibla direction to menu @", (str(datetime.datetime.now())))
61 | self.QiblaItem = Gtk.MenuItem(_("Qibla is %.2f° from True North") % self.silaty.prayertimes.get_qibla())
62 | self.QiblaItem.connect("activate", self.show_qibla)
63 | self.Menu.append(self.QiblaItem)
64 | self.Menu.append(Gtk.SeparatorMenuItem())
65 |
66 | # Add Prayer Times
67 | print ("DEBUG: Adding the prayer times to menu @", (str(datetime.datetime.now())))
68 | self.FajrItem = Gtk.MenuItem(_("Fajr\t\t\t\t\t%s") % self.silaty.get_times(self.silaty.prayertimes.fajr_time()), sensitive=False)
69 | #self.ShurukItem = Gtk.MenuItem(_("Shuruk\t\t\t%s") % self.silaty.get_times(self.silaty.prayertimes.shrouk_time()), sensitive=False)
70 | self.DhuhrItem = Gtk.MenuItem(_("Dhuhr\t\t\t\t%s") % self.silaty.get_times(self.silaty.prayertimes.zuhr_time()), sensitive=False)
71 | self.AsrItem = Gtk.MenuItem(_("Asr\t\t\t\t\t%s") % self.silaty.get_times(self.silaty.prayertimes.asr_time()), sensitive=False)
72 | self.MaghribItem = Gtk.MenuItem(_("Maghrib\t\t\t\t%s") % self.silaty.get_times(self.silaty.prayertimes.maghrib_time()), sensitive=False)
73 | self.IshaItem = Gtk.MenuItem(_("Isha\t\t\t\t\t%s") % self.silaty.get_times(self.silaty.prayertimes.isha_time()), sensitive=False)
74 | self.Menu.append(self.FajrItem)
75 | #self.Menu.append(self.ShurukItem)
76 | self.Menu.append(self.DhuhrItem)
77 | self.Menu.append(self.AsrItem)
78 | self.Menu.append(self.MaghribItem)
79 | self.Menu.append(self.IshaItem)
80 | self.Menu.append(Gtk.SeparatorMenuItem())
81 |
82 | print ("DEBUG: Adding Next prayer to menu @", (str(datetime.datetime.now())))
83 | self.NextPrayerItem = Gtk.MenuItem(_('Next Prayer'), sensitive=False)# Next PrayerTime's Item, it shows you information about the next prayer
84 | self.Menu.append(self.NextPrayerItem)
85 | self.Menu.append(Gtk.SeparatorMenuItem())
86 |
87 | print ("DEBUG: Adding About, Settings and Quit to menu @", (str(datetime.datetime.now())))
88 | # The Last 3 menu items never change and don't need to be updated
89 | AboutItem = Gtk.MenuItem(_('About'))
90 | self.Menu.append(AboutItem)
91 | AboutItem.connect('activate',self.about_dialog, None)
92 |
93 | SettingsItem = Gtk.MenuItem(_('Settings'))
94 | self.Menu.append(SettingsItem)
95 | SettingsItem.connect('activate', self.show_settings, None)
96 |
97 | ExitItem = Gtk.MenuItem(_('Quit'))
98 | self.Menu.append(ExitItem)
99 | ExitItem.connect('activate', self.quit)
100 |
101 | print ("DEBUG: starting mainloop @", (str(datetime.datetime.now())))
102 | self.currentprayer = self.silaty.prayertimes.next_prayer()
103 | self.loop()# Run Application's loop
104 | self.Menu.show_all()# Show All Items
105 | self.Indicator.set_menu(self.Menu)# Assign Menu To Indicator
106 | self.Gobjectloop = GLib.timeout_add_seconds(1, self.loop)# Run loop
107 |
108 | def loop(self):
109 | global NextPrayerDT
110 | self.silaty.prayertimes.calculate()# Calculate PrayerTimes
111 |
112 | # Update City menu item
113 | self.CityItem.set_label(_("Location: %s") % self.silaty.prayertimes.options.city)
114 |
115 | # Update Hijri Date Menu item
116 | self.HijriDateItem.set_label(self.get_hijri_date())
117 |
118 | # Update Qibla Menu item
119 | self.QiblaItem.set_label(_("Qibla is %.2f° from True North") % self.silaty.prayertimes.get_qibla())
120 |
121 | # Update Prayer Times items
122 | self.FajrItem.set_label(_("Fajr\t\t\t\t\t%s") % self.silaty.get_times(self.silaty.prayertimes.fajr_time()))
123 | #self.ShurukItem.set_label(_("Shuruk\t\t\t%s") % self.silaty.get_times(self.silaty.prayertimes.shrouk_time()))
124 | self.DhuhrItem.set_label(_("Dhuhr\t\t\t\t%s") % self.silaty.get_times(self.silaty.prayertimes.zuhr_time()))
125 | self.AsrItem.set_label(_("Asr\t\t\t\t\t%s") % self.silaty.get_times(self.silaty.prayertimes.asr_time()))
126 | self.MaghribItem.set_label(_("Maghrib\t\t\t\t%s") % self.silaty.get_times(self.silaty.prayertimes.maghrib_time()))
127 | self.IshaItem.set_label(_("Isha\t\t\t\t\t%s") % self.silaty.get_times(self.silaty.prayertimes.isha_time()))
128 |
129 | nextprayer = self.silaty.prayertimes.next_prayer()
130 | tonextprayer = self.silaty.prayertimes.time_to_next_prayer()
131 |
132 | # Update displayed prayer
133 | if (nextprayer != self.currentprayer) and self.silaty.is_visible():
134 | self.silaty.homebox.emit("prayers-updated", _(nextprayer))
135 | self.currentprayer = nextprayer
136 |
137 | self.NextPrayerItem.set_label(_("%s until %s") % (self.secs_to_hrtime(tonextprayer.seconds), _(nextprayer)))
138 | self.silaty.headerbar.set_title(_("%s until %s") % (self.secs_to_hrtime(tonextprayer.seconds), _(nextprayer)))
139 | self.Indicator.set_title(_("%s in %s") % (_(nextprayer), (self.secs_to_nrtime(tonextprayer.seconds))))
140 |
141 | if self.silaty.prayertimes.options.iconlabel == True:
142 | self.Indicator.set_label(_("%s in %s") % (_(nextprayer), (self.secs_to_nrtime(tonextprayer.seconds))),"")
143 | else:
144 | self.Indicator.set_label("","")
145 | return True
146 |
147 | def secs_to_hrtime(self, secs):
148 | # Transform Seconds into Hours and Minutes
149 | hours = secs//3600
150 | minutes = (secs//60)%60
151 | minutes += 1 # correct minutes (to avoid values like "0min")
152 | if minutes == 60:
153 | hours += 1
154 | return _("%s Hours") % str(hours)
155 | elif hours == 0:
156 | return _("%s Minutes") % str(minutes)
157 | else:
158 | return _("%s Hours and %s Minutes") % (str(hours), str(minutes))
159 |
160 | def secs_to_nrtime(self, secs):
161 | # Transform Seconds into Hours and Minutes
162 | # Using the same standard in iPray
163 | hours = secs//3600
164 | minutes = (secs//60)%60
165 | minutes += 1 # correct minutes (to avoid values like "0min")
166 | if minutes == 60:
167 | hours += 1
168 | return _("%shr") % str(hours)
169 | elif hours == 0:
170 | return _("%smin") % str(minutes)
171 | else:
172 | return _("%shr %smin") % (str(hours), str(minutes))
173 |
174 | def icon(self):
175 | # Get Icon
176 | print ("DEBUG: getting Icons @", (str(datetime.datetime.now())))
177 | PathDir = os.path.dirname(os.path.realpath(__file__)) + "/icons/hicolor/scalable/silaty-indicator.svg"
178 | #print (PathDir)
179 |
180 | if os.path.exists(PathDir):
181 | print ("DEBUG: icon found in the OS @", (str(datetime.datetime.now())))
182 | return PathDir
183 |
184 | else:
185 | print ("ERROR: Cannot find icon : silaty-indicator.svg @ %s" % (str(datetime.datetime.now())), file=sys.stderr)
186 | print ("DEBUG: silaty-indicator QUITING @", (str(datetime.datetime.now())))
187 | sys.exit(1)
188 |
189 | def get_hijri_date(self):
190 | wd = datetime.datetime.now().strftime("%A")
191 | calc = HijriCal(self.silaty.prayertimes.options.hijrical_adjustment)
192 | h_months = ['Muharram ', 'Safar', 'Rabi al Awwal', 'Rabi al Akhira', 'Jumada al Ula', 'Jumada al Akhira', 'Rajab', "Sha'ban", 'Ramadan', 'Shawwal', "Dhu al Qa'da", 'Dhu al Hijja']
193 | h_year, h_month, h_day, h_week_day = calc.today
194 | h_date = '%i %s %i' % ( h_day, _(h_months[int(h_month-1)]), h_year)
195 | return (_('%s, %s') % (_(wd), h_date))
196 |
197 | def show_home(self, widget):
198 | self.show_window("home")
199 |
200 | def show_qibla(self, widget):
201 | self.show_window("qibla")
202 |
203 | def show_settings(self, widget, data):
204 | self.show_window("options")
205 |
206 | def show_window(self, active_tab_name):
207 | # Show main window
208 | #print ('DEBUG: window is visible: %s, active: %s' % (self.silaty.is_visible(), self.silaty.is_active()))
209 | if not self.silaty.is_visible():
210 | self.silaty.show_all()
211 | elif not self.silaty.is_active():
212 | self.silaty.present()
213 | # Set active tab
214 | current_tab_name = self.silaty.sidebar.stack.get_visible_child_name()
215 | if (current_tab_name != active_tab_name):
216 | # If another tab was activated before, set its state to OFF
217 | index = self.silaty.sidebar.stackchildnames.index(current_tab_name)
218 | self.silaty.sidebar.get_child(index).state = SideBarButtonState.OFF
219 | # Activate/show new tab
220 | self.silaty.sidebar.stack.set_visible_child_name(active_tab_name)
221 | self.silaty.sidebar.emit("window-shown")
222 |
223 | def about_dialog(self, widget, data=None):# The About Dialog
224 | print ("DEBUG: opening about dialog @", (str(datetime.datetime.now())))
225 | about_dialog = Gtk.AboutDialog()
226 | if self.silaty.is_visible():
227 | about_dialog.set_transient_for(self.silaty)
228 | else:
229 | about_dialog.set_position(Gtk.WindowPosition.CENTER)
230 | logo = GdkPixbuf.Pixbuf.new_from_file(os.path.dirname(os.path.realpath(__file__)) + "/icons/hicolor/48x48/apps/silaty.svg")
231 | about_dialog.set_logo(logo)
232 | about_dialog.set_program_name(_("Silaty"))
233 | about_dialog.set_website("https://github.com/AXeL-dev/Silaty")
234 | about_dialog.set_website_label(_("GitHub Project Page"))
235 | about_dialog.set_authors(["AXeL-dev (Maintainer)", "Jesse Wayde Brandão (Lead Developer)",\
236 | "Mohamed Alaa (Developer)","Eslam Mostafa (Developer)",\
237 | "Ahmed Youssef (Developer)"])
238 | about_dialog.set_artists(["Mustapha Asbbar (Designer)"])
239 | about_dialog.set_license('''Silaty, A Prayer Times Reminder Application.
240 | Copyright © 2021 Silaty Team
241 |
242 | This program is free software: you can redistribute it and/or modify
243 | it under the terms of the GNU General Public License as published by
244 | the Free Software Foundation, either version 3 of the License, or
245 | (at your option) any later version.
246 |
247 | This program is distributed in the hope that it will be useful,
248 | but WITHOUT ANY WARRANTY; without even the implied warranty of
249 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
250 | GNU General Public License for more details.
251 |
252 | You should have received a copy of the GNU General Public License
253 | along with this program. If not, see .''')
254 | about_dialog.set_version("1.5")
255 | about_dialog.set_comments(_("A neat Prayer Time Reminder App.\n Simple and complete so no prayer is missed"))
256 | about_dialog.set_copyright(_("Copyright © %s Silaty Team") % '2021')
257 | about_dialog.run()
258 | about_dialog.destroy()
259 |
260 | def quit(self, widget):
261 | self.silaty.prayertimes.options.save_options()
262 | self.silaty.destroy()
263 | Gtk.main_quit()
264 |
265 | def main(self):
266 | Gtk.main()
267 | print ("DEBUG: starting/stopping GTK @", (str(datetime.datetime.now())))
268 |
269 | if __name__ == '__main__':
270 | ipm = SilatyIndicator()
271 | ipm.main()
272 |
--------------------------------------------------------------------------------
/silaty.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Version=1.0
3 | Name=Silaty
4 | Comment=A neat prayer reminder application
5 | Exec=/usr/local/bin/silaty-indicator
6 | Icon=silaty
7 | Terminal=false
8 | StartupNotify=true
9 | Type=Application
10 | Categories=GNOME;GTK;Utility;
11 | Name[en_US]=Silaty
--------------------------------------------------------------------------------
/snap/snapcraft.yaml:
--------------------------------------------------------------------------------
1 | name: silaty # you probably want to 'snapcraft register '
2 | base: core18 # the base snap is the execution environment for this snap
3 | version: '1.4' # just for humans, typically '1.2+git' or '1.3.2'
4 | summary: A neat prayer reminder app # 79 char long summary
5 | description: |
6 | A neat prayer reminder app
7 |
8 | grade: stable # must be 'stable' to release into candidate/stable channels
9 | confinement: strict # use 'strict' once you have the right plugs and slots
10 |
11 | parts:
12 | silaty:
13 | plugin: python
14 | python-version: python3
15 | source: .
16 | build-packages:
17 | - python3-pip
18 | - libpulse-dev
19 | stage-packages:
20 | - gir1.2-gtk-3.0
21 | - gir1.2-appindicator3-0.1
22 | - gir1.2-notify-0.7
23 | - libgstreamer1.0-0
24 | - gstreamer1.0-plugins-base
25 | - gstreamer1.0-plugins-good
26 | - gstreamer1.0-pulseaudio
27 | - python3-gst-1.0
28 | - libpulse0
29 | - libglu1-mesa
30 | - freeglut3
31 | - libgpm2
32 | - libslang2
33 | python-packages:
34 | - setuptools
35 | - PyGObject
36 | - pip
37 | - wheel
38 | override-stage: |
39 | # copy project files
40 | cp -r $SNAPCRAFT_PART_BUILD/* $SNAPCRAFT_PART_INSTALL
41 | # copy icons
42 | cp $SNAPCRAFT_PART_BUILD/silaty-indicator.py $SNAPCRAFT_PART_INSTALL/silaty-indicator
43 | cp $SNAPCRAFT_PART_BUILD/icons/hicolor/128x128/apps/silaty.svg $SNAPCRAFT_PART_INSTALL/usr/share/icons/hicolor/scalable/apps/
44 | cp $SNAPCRAFT_PART_BUILD/icons/hicolor/128x128/apps/silaty.svg $SNAPCRAFT_PART_INSTALL/usr/share/icons/hicolor/128x128/apps/
45 | cp $SNAPCRAFT_PART_BUILD/icons/hicolor/48x48/apps/silaty.svg $SNAPCRAFT_PART_INSTALL/usr/share/icons/hicolor/48x48/apps/
46 | cp $SNAPCRAFT_PART_BUILD/icons/hicolor/24x24/apps/silaty.svg $SNAPCRAFT_PART_INSTALL/usr/share/icons/hicolor/24x24/apps/
47 | snapcraftctl stage
48 |
49 | apps:
50 | silaty:
51 | command: usr/bin/python3 $SNAP/silaty-indicator
52 | desktop: $SNAPCRAFT_PROJECT_DIR/silaty.desktop
53 | extensions: [gnome-3-34]
54 | plugs:
55 | - desktop
56 | - audio-playback
57 | slots:
58 | - dbus-daemon
59 | common-id: com.github.AXeL-dev.silaty
60 |
61 | slots:
62 | dbus-daemon:
63 | interface: dbus
64 | bus: session
65 | name: com.github.AXeL-dev.silaty
--------------------------------------------------------------------------------
/translate.py:
--------------------------------------------------------------------------------
1 | # Silaty
2 | # Copyright (c) 2018 - 2021 AXeL
3 | # Copyright (c) 2014 - 2015 Jessewb786
4 |
5 | import os
6 | import json
7 |
8 | languages = {
9 | 'English': 'en.json',
10 | 'Arabic': 'ar.json',
11 | 'French': 'fr.json',
12 | 'Spanish': 'es.json',
13 | }
14 | language = 'English'
15 | translations = {}
16 |
17 | def set_language(lang):
18 | global language
19 | language = lang
20 | load_translations()
21 |
22 | def load_language_file(lang):
23 | try:
24 | return open(os.path.dirname(os.path.realpath(__file__)) + '/lang/' + languages[lang])
25 | except FileNotFoundError:
26 | return open(os.path.dirname(os.path.realpath(__file__)) + '/lang/' + languages['English'])
27 |
28 | def load_translations():
29 | global translations
30 | file = load_language_file(language)
31 | try:
32 | translations = json.load(file)
33 | except json.decoder.JSONDecodeError:
34 | translations = {}
35 |
36 | def translate_text(text):
37 | #print ("DEBUG: translate text '%s' in '%s'" % (text, language))
38 | if text in translations:
39 | return translations[text]
40 | else:
41 | return text
42 |
--------------------------------------------------------------------------------
/uninstall.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ "$(id -u)" != "0" ]; then
4 | echo “This script must be run as root” 2>&1
5 | exit 1
6 | fi
7 |
8 | rm -rf /usr/share/silaty
9 | rm -f /usr/share/applications/silaty.desktop
10 | rm -f /etc/xdg/autostart/silaty.desktop
11 | rm -f /usr/local/bin/silaty-indicator
12 |
13 | rm -f /usr/share/icons/hicolor/128x128/apps/silaty.svg
14 | rm -f /usr/share/icons/hicolor/48x48/apps/silaty.svg
15 | rm -f /usr/share/icons/hicolor/24x24/apps/silaty.svg
16 | rm -f /usr/share/icons/hicolor/scalable/apps/silaty.svg
17 |
18 | rm -f /usr/share/icons/hicolor/scalable/apps/silaty-indicator.svg
--------------------------------------------------------------------------------