menu22.py

Download
import os, datetime, math, threading, json
import customtkinter as ctk
from tkinter import messagebox
import ephem

BASE_DIR = os.path.dirname(os.path.abspath(__file__))

# ---> SILAKAN COPAS HIJRI_DB LENGKAP DI SINI <---
HIJRI_DB = {
    1447: [["Muharam", "", "", 30], ["Safar", "", "", 29], ["Rabiulawal", "", "", 30], ["Rabiulakhir", "", "", 30], ["Jumadilawal", "", "", 29], ["Jumadilakhir", "", "", 30], ["Rajab", "", "", 30], ["Syakban", "", "", 29], ["Ramadan", "Rabu Legi", "18-Feb-2026", 30]],
    1448: [["Muharam", "", "", 30], ["Safar", "", "", 29], ["Rabiulawal", "", "", 30], ["Rabiulakhir", "", "", 30], ["Jumadilawal", "", "", 29], ["Jumadilakhir", "", "", 30], ["Rajab", "", "", 30], ["Syakban", "", "", 29], ["Ramadan", "Senin", "08-Feb-2027", 29]],
}

try:
    DB_JSON_PATH = os.path.join(BASE_DIR, "db_hijriah.json")
    if os.path.exists(DB_JSON_PATH):
        with open(DB_JSON_PATH, "r", encoding="utf-8") as f:
            HIJRI_DB.update({int(k): v for k, v in json.load(f).items()})
except Exception: pass

class Menu22App(ctk.CTk):
    def __init__(self):
        super().__init__()
        self.title("Tabel Tinggi Hilal Ramadhan (Modul 22)")
        self.geometry("1100x650")
        ctk.set_appearance_mode("Dark")
        self.setup_ui()

    def get_header(self, width):
        return "\n".join(line.center(width) for line in ["By the Name of Allah", "KHGT Times 7.2 - Data Ketinggian Ramadhan"])

    def setup_ui(self):
        self.sidebar = ctk.CTkFrame(self, width=250)
        self.sidebar.pack(side="left", fill="y", padx=10, pady=10)
        
        ctk.CTkLabel(self.sidebar, text="TABEL TINGGI HILAL\n(RAMADHAN)", font=("Segoe UI", 16, "bold"), text_color="#00E5FF").pack(pady=20)
        
        self.btn_hitung = ctk.CTkButton(self.sidebar, text="▶ PROSES DATA", font=("Segoe UI", 12, "bold"), command=self.hitung_tinggi_ramadhan, height=45)
        self.btn_hitung.pack(pady=20, fill="x", padx=20)
        self.lbl_status = ctk.CTkLabel(self.sidebar, text="Sistem Siap", text_color="#00E676")
        self.lbl_status.pack()

        self.textbox = ctk.CTkTextbox(self, font=("Consolas", 13), wrap="none")
        self.textbox.pack(side="right", fill="both", expand=True, padx=10, pady=10)
        self.textbox.insert("1.0", "Klik '▶ PROSES DATA' untuk mengekstrak tabel ketinggian hilal (Altitude).")
        self.textbox.configure(state="disabled")

    def hitung_tinggi_ramadhan(self):
        threading.Thread(target=self._proses_tabel, daemon=True).start()

    def _proses_tabel(self):
        self.after(0, lambda: self.lbl_status.configure(text="Mengekstrak Data Altitude...", text_color="#FFAB40"))
        self.after(0, lambda: self.btn_hitung.configure(state="disabled"))
        self.after(0, lambda: self.textbox.configure(state="normal"))
        self.after(0, lambda: self.textbox.delete("1.0", "end"))
        
        output_lines = [
            self.get_header(130),
            "[ DATA KETINGGIAN HILAL 50 TAHUN (RAMADHAN 1447H - 1496H) ]".center(130),
            "Metode: Akselerasi Database KHGT vs Toposentrik Sabang".center(130),
            "=" * 130,
            f"{'Tahun':<7} | {'Ijtimak (UTC)':<16} | {'KHGT: Parameter Global (Geo)':<40} | {'MABIMS: Sabang (Topo)':<30} | {'Status'}",
            "-" * 130
        ]

        sabang = ephem.Observer()
        sabang.lat, sabang.lon = math.radians(5.8942), math.radians(95.3184)
        sabang.elevation, sabang.pressure, sabang.temp = 0, 1010, 25
        sun, moon = ephem.Sun(), ephem.Moon()
        bulan_map = {"Jan":1, "Feb":2, "Mar":3, "Apr":4, "May":5, "Jun":6, "Jul":7, "Aug":8, "Sep":9, "Oct":10, "Nov":11, "Dec":12}

        for thn_h in range(1447, 1497):
            try:
                if thn_h not in HIJRI_DB: continue
                # Index 8 = Ramadhan
                parts = HIJRI_DB[thn_h][8][2].split('-')
                dt_khgt = datetime.datetime(int(parts[2]), bulan_map.get(parts[1], 1), int(parts[0]))
                dt_rukyat = dt_khgt - datetime.timedelta(days=1)
                
                ijtimak = ephem.previous_new_moon(ephem.Date(dt_rukyat) + 2)
                str_ijtimak = ijtimak.datetime().strftime("%d-%b %H:%M")

                str_khgt = "Terpenuhi (Alt >= 5°, Eln >= 8°)"

                sabang.date = ephem.Date(dt_rukyat.replace(hour=0, minute=0, second=0))
                try: waktu_sunset = sabang.next_setting(sun)
                except: waktu_sunset = ephem.Date(dt_rukyat.replace(hour=11, minute=30, second=0))
                
                sabang.date = waktu_sunset
                sun.compute(sabang); moon.compute(sabang)
                
                alt_s = math.degrees(moon.alt)
                eln_s = math.degrees(ephem.separation(sun, moon))
                umur_s = (waktu_sunset - ijtimak) * 24 
                
                if alt_s >= 3.0 and eln_s >= 6.4 and umur_s > 0:
                    status_s, kesimpulan = "Lolos", "Serentak"
                else:
                    status_s, kesimpulan = "Belum", "Beda (MABIMS Mundur)"
                
                str_sabang = f"Alt:{alt_s:5.2f}°, Eln:{eln_s:5.2f}° [{status_s}]"
                output_lines.append(f"{thn_h} H | {str_ijtimak:<16} | {str_khgt:<40} | {str_sabang:<30} | {kesimpulan}")
                
                if (thn_h - 1446) % 10 == 0 and thn_h != 1496: output_lines.append("-" * 130)

            except Exception as err:
                output_lines.append(f"{thn_h} H | Error: {str(err)}")

        output_lines.append("=" * 130)
        self.after(0, lambda: self.textbox.insert("1.0", "\n".join(output_lines)))
        self.after(0, lambda: self.textbox.configure(state="disabled"))
        self.after(0, lambda: self.lbl_status.configure(text="Selesai", text_color="#00E676"))
        self.after(0, lambda: self.btn_hitung.configure(state="normal"))

if __name__ == "__main__":
    app = Menu22App()
    app.mainloop()