|
|
@@ -3,11 +3,14 @@ import customtkinter as ctk
|
|
|
|
import threading
|
|
|
|
import threading
|
|
|
|
import json
|
|
|
|
import json
|
|
|
|
import os
|
|
|
|
import os
|
|
|
|
|
|
|
|
import webbrowser
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app = ctk.CTk()
|
|
|
|
app = ctk.CTk()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def toggleAppearanceMode():
|
|
|
|
def toggleAppearanceMode():
|
|
|
|
if changeAppearanceMode.get() == 0:
|
|
|
|
if changeAppearanceMode.get() == 0:
|
|
|
|
mode = "dark"
|
|
|
|
mode = "dark"
|
|
|
@@ -20,14 +23,14 @@ def toggleAppearanceMode():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
with open("config.json", "r") as f:
|
|
|
|
with open("config/config.json", "r") as f:
|
|
|
|
config = json.load(f)
|
|
|
|
config = json.load(f)
|
|
|
|
except:
|
|
|
|
except:
|
|
|
|
config = {}
|
|
|
|
config = {}
|
|
|
|
|
|
|
|
|
|
|
|
config["appearance"] = mode
|
|
|
|
config["appearance"] = mode
|
|
|
|
|
|
|
|
|
|
|
|
with open("config.json", "w") as f:
|
|
|
|
with open("config/config.json", "w") as f:
|
|
|
|
json.dump(config, f, indent=4)
|
|
|
|
json.dump(config, f, indent=4)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -48,14 +51,14 @@ def toggleFromMetric():
|
|
|
|
checkSystem()
|
|
|
|
checkSystem()
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
with open("config.json", "r") as f:
|
|
|
|
with open("config/config.json", "r") as f:
|
|
|
|
config = json.load(f)
|
|
|
|
config = json.load(f)
|
|
|
|
except:
|
|
|
|
except:
|
|
|
|
config = {}
|
|
|
|
config = {}
|
|
|
|
|
|
|
|
|
|
|
|
config["system"] = system
|
|
|
|
config["system"] = system
|
|
|
|
|
|
|
|
|
|
|
|
with open("config.json", "w") as f:
|
|
|
|
with open("config/config.json", "w") as f:
|
|
|
|
json.dump(config, f, indent=4)
|
|
|
|
json.dump(config, f, indent=4)
|
|
|
|
|
|
|
|
|
|
|
|
if resultPage.winfo_ismapped():
|
|
|
|
if resultPage.winfo_ismapped():
|
|
|
@@ -71,8 +74,8 @@ changeAppearanceMode.pack(anchor="w", padx=10, pady=5)
|
|
|
|
changeFromMetric = ctk.CTkSwitch(switchFrame, text="Change to Imperial System", command=toggleFromMetric)
|
|
|
|
changeFromMetric = ctk.CTkSwitch(switchFrame, text="Change to Imperial System", command=toggleFromMetric)
|
|
|
|
changeFromMetric.pack(anchor="w", padx=10, pady=5)
|
|
|
|
changeFromMetric.pack(anchor="w", padx=10, pady=5)
|
|
|
|
|
|
|
|
|
|
|
|
if os.path.exists("config.json"):
|
|
|
|
if os.path.exists("config/config.json"):
|
|
|
|
with open("config.json", "r") as f:
|
|
|
|
with open("config/config.json", "r") as f:
|
|
|
|
config = json.load(f)
|
|
|
|
config = json.load(f)
|
|
|
|
mode = config.get("appearance")
|
|
|
|
mode = config.get("appearance")
|
|
|
|
if mode == "light":
|
|
|
|
if mode == "light":
|
|
|
@@ -140,23 +143,21 @@ def get_current_color(widget="CTkFrame"):
|
|
|
|
def checkSystem():
|
|
|
|
def checkSystem():
|
|
|
|
|
|
|
|
|
|
|
|
global degrees
|
|
|
|
global degrees
|
|
|
|
|
|
|
|
global speed
|
|
|
|
if system == "metric":
|
|
|
|
if system == "metric":
|
|
|
|
degrees = "°C"
|
|
|
|
degrees = "°C"
|
|
|
|
|
|
|
|
speed = "m/s"
|
|
|
|
changeFromMetric.set(False)
|
|
|
|
changeFromMetric.set(False)
|
|
|
|
|
|
|
|
|
|
|
|
elif system == "imperial":
|
|
|
|
elif system == "imperial":
|
|
|
|
degrees = "°F"
|
|
|
|
degrees = "°F"
|
|
|
|
|
|
|
|
speed = "mph"
|
|
|
|
changeFromMetric.set(True)
|
|
|
|
changeFromMetric.set(True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if os.path.exists("config/config.json"):
|
|
|
|
|
|
|
|
with open("config/config.json", "r") as f:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if os.path.exists("config.json"):
|
|
|
|
|
|
|
|
with open("config.json", "r") as f:
|
|
|
|
|
|
|
|
config = json.load(f)
|
|
|
|
config = json.load(f)
|
|
|
|
system = config.get("system", "metric")
|
|
|
|
system = config.get("system", "metric")
|
|
|
|
checkSystem()
|
|
|
|
checkSystem()
|
|
|
@@ -164,11 +165,14 @@ if os.path.exists("config.json"):
|
|
|
|
searchPage = ctk.CTkFrame(app, fg_color="transparent")
|
|
|
|
searchPage = ctk.CTkFrame(app, fg_color="transparent")
|
|
|
|
resultPage = ctk.CTkFrame(app, fg_color="transparent")
|
|
|
|
resultPage = ctk.CTkFrame(app, fg_color="transparent")
|
|
|
|
|
|
|
|
|
|
|
|
if os.path.exists("config.json"):
|
|
|
|
if os.path.exists("config/API.config.json"):
|
|
|
|
with open("config.json", "r") as f:
|
|
|
|
with open("config/API.config.json", "r") as f:
|
|
|
|
config = json.load(f)
|
|
|
|
config = json.load(f)
|
|
|
|
APIKey = config.get("api_key")
|
|
|
|
APIKey = config.get("api_key")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def openWeatherLink(event):
|
|
|
|
|
|
|
|
webbrowser.open("https://openweathermap.org/api")
|
|
|
|
|
|
|
|
|
|
|
|
def openAPIPopup():
|
|
|
|
def openAPIPopup():
|
|
|
|
global popup
|
|
|
|
global popup
|
|
|
|
|
|
|
|
|
|
|
@@ -190,10 +194,14 @@ def openAPIPopup():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
APIlabel = ctk.CTkLabel(popup, text="Enter your API key:")
|
|
|
|
APIlabel = ctk.CTkLabel(popup, text="Enter your API key:")
|
|
|
|
APIlabel.pack(pady=20)
|
|
|
|
APIlabel.pack(pady=(15, 5))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
APIKeyGet = ctk.CTkLabel(popup, text="How to get free API key", text_color="#3366d6", cursor="hand2")
|
|
|
|
|
|
|
|
APIKeyGet.bind("<Button-1>", openWeatherLink)
|
|
|
|
|
|
|
|
APIKeyGet.pack(pady=5)
|
|
|
|
|
|
|
|
|
|
|
|
APIEntry = ctk.CTkEntry(popup, placeholder_text="API key...")
|
|
|
|
APIEntry = ctk.CTkEntry(popup, placeholder_text="API key...")
|
|
|
|
APIEntry.pack(pady=10)
|
|
|
|
APIEntry.pack(pady=0)
|
|
|
|
|
|
|
|
|
|
|
|
APIErrorFrame = ctk.CTkFrame(popup, width=450, height=20)
|
|
|
|
APIErrorFrame = ctk.CTkFrame(popup, width=450, height=20)
|
|
|
|
APIErrorLabel = ctk.CTkLabel(APIErrorFrame, text="", font=("Arial", 14))
|
|
|
|
APIErrorLabel = ctk.CTkLabel(APIErrorFrame, text="", font=("Arial", 14))
|
|
|
@@ -212,19 +220,18 @@ def openAPIPopup():
|
|
|
|
APIKey = APIEntry.get()
|
|
|
|
APIKey = APIEntry.get()
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
with open("config.json", "r") as f:
|
|
|
|
with open("config/API.config.json", "r") as f:
|
|
|
|
config = json.load(f)
|
|
|
|
config = json.load(f)
|
|
|
|
except:
|
|
|
|
except:
|
|
|
|
config = {}
|
|
|
|
config = {}
|
|
|
|
|
|
|
|
|
|
|
|
config["api_key"] = APIKey
|
|
|
|
config["api_key"] = APIKey
|
|
|
|
|
|
|
|
|
|
|
|
with open("config.json", "w") as f:
|
|
|
|
with open("config/API.config.json", "w") as f:
|
|
|
|
json.dump(config, f, indent=4)
|
|
|
|
json.dump(config, f, indent=4)
|
|
|
|
|
|
|
|
|
|
|
|
if APIcode == 401:
|
|
|
|
if APIcode == 401:
|
|
|
|
def show_error():
|
|
|
|
def show_error():
|
|
|
|
print("401")
|
|
|
|
|
|
|
|
APIErrorFrame.pack()
|
|
|
|
APIErrorFrame.pack()
|
|
|
|
APIErrorLabel.configure(text="Couldn't access the API key!")
|
|
|
|
APIErrorLabel.configure(text="Couldn't access the API key!")
|
|
|
|
APIErrorLabel.pack(padx=10)
|
|
|
|
APIErrorLabel.pack(padx=10)
|
|
|
@@ -263,9 +270,6 @@ if not APIKey:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
searchPage.pack(fill="both", expand=True)
|
|
|
|
searchPage.pack(fill="both", expand=True)
|
|
|
|
searchPage.pack(pady=200)
|
|
|
|
searchPage.pack(pady=200)
|
|
|
|
|
|
|
|
|
|
|
@@ -304,10 +308,22 @@ weatherGeneralFrame = ctk.CTkFrame(cardsFrame, width=500, height=350)
|
|
|
|
weatherGeneralFrame.pack(side="left", expand=True, fill="both", padx=10)
|
|
|
|
weatherGeneralFrame.pack(side="left", expand=True, fill="both", padx=10)
|
|
|
|
weatherGeneralFrame.pack_propagate(False)
|
|
|
|
weatherGeneralFrame.pack_propagate(False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
weatherGeneralTitle = ctk.CTkLabel(weatherGeneralFrame, text="General:", font=("Arial", 45, "bold"))
|
|
|
|
|
|
|
|
weatherGeneralTitle.pack(expand=True, fill="both", pady=(20,10))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
weatherGeneralLabel = ctk.CTkLabel(weatherGeneralFrame, font=("Arial", 25))
|
|
|
|
|
|
|
|
weatherGeneralLabel.pack(expand=True, anchor = "n")
|
|
|
|
|
|
|
|
|
|
|
|
weatherWindFrame = ctk.CTkFrame(cardsFrame, width=500, height=350)
|
|
|
|
weatherWindFrame = ctk.CTkFrame(cardsFrame, width=500, height=350)
|
|
|
|
weatherWindFrame.pack(side="left", expand=True, fill="both", padx=10)
|
|
|
|
weatherWindFrame.pack(side="left", expand=True, fill="both", padx=10)
|
|
|
|
weatherWindFrame.pack_propagate(False)
|
|
|
|
weatherWindFrame.pack_propagate(False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
weatherWindTitle = ctk.CTkLabel(weatherWindFrame, text="Wind", font=("Arial", 45, "bold"))
|
|
|
|
|
|
|
|
weatherWindTitle.pack(expand=True, fill="both", pady=(20,10))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
weatherWindLabel = ctk.CTkLabel(weatherWindFrame, font=("Arial", 25))
|
|
|
|
|
|
|
|
weatherWindLabel.pack(expand=True, anchor = "n")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##################################################
|
|
|
|
##################################################
|
|
|
|
#### Return Button ####
|
|
|
|
#### Return Button ####
|
|
|
@@ -332,8 +348,7 @@ def searchWeather():
|
|
|
|
|
|
|
|
|
|
|
|
url = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={APIKey}&units={system}&lang=en"
|
|
|
|
url = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={APIKey}&units={system}&lang=en"
|
|
|
|
|
|
|
|
|
|
|
|
print(system)
|
|
|
|
|
|
|
|
print(url)
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
response = requests.get(url, timeout=5)
|
|
|
|
response = requests.get(url, timeout=5)
|
|
|
|
APIcode = response.status_code
|
|
|
|
APIcode = response.status_code
|
|
|
@@ -345,16 +360,32 @@ def searchWeather():
|
|
|
|
feels_like = data["main"]["feels_like"]
|
|
|
|
feels_like = data["main"]["feels_like"]
|
|
|
|
maxTemp = data["main"]["temp_max"]
|
|
|
|
maxTemp = data["main"]["temp_max"]
|
|
|
|
minTemp = data["main"]["temp_min"]
|
|
|
|
minTemp = data["main"]["temp_min"]
|
|
|
|
|
|
|
|
pressure = data["main"]["grnd_level"] / 1000
|
|
|
|
|
|
|
|
humidity = data["main"]["humidity"]
|
|
|
|
|
|
|
|
windSpeed = data["wind"]["speed"]
|
|
|
|
|
|
|
|
windDirection = data["wind"]["deg"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print(data)
|
|
|
|
|
|
|
|
|
|
|
|
def show_result():
|
|
|
|
def show_result():
|
|
|
|
ErrorLabel.configure(text="")
|
|
|
|
ErrorLabel.configure(text="")
|
|
|
|
ErrorFrame.pack_forget()
|
|
|
|
ErrorFrame.pack_forget()
|
|
|
|
|
|
|
|
|
|
|
|
weatherTempLabel.configure(
|
|
|
|
weatherTempLabel.configure(
|
|
|
|
text=f"It is {temp}{degrees} in {city}. \n\n"
|
|
|
|
text=f"The current temperature in {city}\n\n is {temp}{degrees}. \n\n"
|
|
|
|
f"It feels like {feels_like}{degrees} and the \n\n"
|
|
|
|
f"It actually feels like {feels_like}{degrees} and today's \n\n"
|
|
|
|
f"max Temperature is {maxTemp}{degrees}, while\n\n"
|
|
|
|
f"temperature will drop to a minimum of {minTemp}{degrees},\n\n"
|
|
|
|
f"the minimum Temperature is {minTemp}{degrees}"
|
|
|
|
f"while the maximum temperature expected \n\n today is {maxTemp}{degrees}"
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
weatherGeneralLabel.configure(
|
|
|
|
|
|
|
|
text=f"The atmospheric pressure measured at ground \n\n"
|
|
|
|
|
|
|
|
f"level is {pressure} bar. \n\n"
|
|
|
|
|
|
|
|
f"The current relative air humidity stands at {humidity}%"
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
weatherWindLabel.configure(
|
|
|
|
|
|
|
|
text=f"The wind is currently blowing at a \n\n speed of {windSpeed}{speed}.\n\n"
|
|
|
|
|
|
|
|
f"The wind direction is coming from {windDirection}°."
|
|
|
|
)
|
|
|
|
)
|
|
|
|
searchPage.pack_forget()
|
|
|
|
searchPage.pack_forget()
|
|
|
|
resultPage.pack(fill="both", expand=True)
|
|
|
|
resultPage.pack(fill="both", expand=True)
|
|
|
|