Compare commits
1
Commits
71ffae0026
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
faabb7c82a |
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"api_key": "6da85901a47efe9f943b1a40bbc727e5"
|
"api_key": ""
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,21 @@
|
|||||||
import requests
|
|
||||||
import customtkinter as ctk
|
|
||||||
import threading
|
import threading
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
import customtkinter as ctk
|
||||||
|
except ImportError:
|
||||||
|
subprocess.check_call([sys.executable, "-m", "pip", "install", "customtkinter"])
|
||||||
|
import customtkinter as ctk
|
||||||
|
|
||||||
|
try:
|
||||||
|
import requests
|
||||||
|
except ImportError:
|
||||||
|
subprocess.check_call([sys.executable, "-m", "pip", "install", "requests"])
|
||||||
|
import requests
|
||||||
|
|
||||||
app = ctk.CTk()
|
app = ctk.CTk()
|
||||||
|
|
||||||
@@ -65,6 +75,8 @@ def toggleFromMetric():
|
|||||||
doSearch()
|
doSearch()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
switchFrame = ctk.CTkFrame(app, fg_color="transparent")
|
switchFrame = ctk.CTkFrame(app, fg_color="transparent")
|
||||||
switchFrame.pack(anchor="ne")
|
switchFrame.pack(anchor="ne")
|
||||||
|
|
||||||
@@ -74,6 +86,9 @@ 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/config.json"):
|
if os.path.exists("config/config.json"):
|
||||||
with open("config/config.json", "r") as f:
|
with open("config/config.json", "r") as f:
|
||||||
config = json.load(f)
|
config = json.load(f)
|
||||||
@@ -98,6 +113,38 @@ APIKey = None
|
|||||||
system = "metric"
|
system = "metric"
|
||||||
degrees = "°C"
|
degrees = "°C"
|
||||||
|
|
||||||
|
def readFavourite():
|
||||||
|
global favouriteVar
|
||||||
|
fav = ""
|
||||||
|
favouriteVar = ctk.BooleanVar(value=False)
|
||||||
|
|
||||||
|
with open("config/config.json", "r") as f:
|
||||||
|
config = json.load(f)
|
||||||
|
fav = config["fav"]
|
||||||
|
|
||||||
|
def saveFavourite():
|
||||||
|
with open("config/config.json", "r") as f:
|
||||||
|
config = json.load(f)
|
||||||
|
|
||||||
|
if "favourite" not in config:
|
||||||
|
config["favourite"] = []
|
||||||
|
|
||||||
|
if favouriteCheck.get() == 1:
|
||||||
|
if city not in config["favourite"]:
|
||||||
|
config["favourite"].append(city)
|
||||||
|
else:
|
||||||
|
if city in config["favourite"]:
|
||||||
|
config["favourite"].remove(city)
|
||||||
|
|
||||||
|
with open("config/config.json", "w") as f:
|
||||||
|
json.dump(config, f, indent=4)
|
||||||
|
|
||||||
|
favouriteCheck = ctk.CTkCheckBox(switchFrame, text="Favourite", command=saveFavourite)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def glow_effect(widget, steps=25, start_rgb=(239, 68, 68), delay=30):
|
def glow_effect(widget, steps=25, start_rgb=(239, 68, 68), delay=30):
|
||||||
theme_color = ctk.ThemeManager.theme["CTkFrame"]["fg_color"]
|
theme_color = ctk.ThemeManager.theme["CTkFrame"]["fg_color"]
|
||||||
@@ -126,8 +173,10 @@ def glow_effect(widget, steps=25, start_rgb=(239, 68, 68), delay=30):
|
|||||||
|
|
||||||
def returnButtonClick():
|
def returnButtonClick():
|
||||||
resultPage.pack_forget()
|
resultPage.pack_forget()
|
||||||
|
favPage.pack_forget()
|
||||||
searchPage.pack(fill="both", expand="True")
|
searchPage.pack(fill="both", expand="True")
|
||||||
searchPage.pack(pady=70)
|
searchPage.pack(pady=70)
|
||||||
|
favouriteCheck.pack_forget()
|
||||||
|
|
||||||
|
|
||||||
def get_current_color(widget="CTkFrame"):
|
def get_current_color(widget="CTkFrame"):
|
||||||
@@ -140,6 +189,7 @@ def get_current_color(widget="CTkFrame"):
|
|||||||
return fgColors[0]
|
return fgColors[0]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def checkSystem():
|
def checkSystem():
|
||||||
|
|
||||||
global degrees
|
global degrees
|
||||||
@@ -164,6 +214,7 @@ if os.path.exists("config/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")
|
||||||
|
favPage = ctk.CTkFrame(app, fg_color="transparent")
|
||||||
|
|
||||||
if os.path.exists("config/API.config.json"):
|
if os.path.exists("config/API.config.json"):
|
||||||
with open("config/API.config.json", "r") as f:
|
with open("config/API.config.json", "r") as f:
|
||||||
@@ -196,7 +247,7 @@ def openAPIPopup():
|
|||||||
APIlabel = ctk.CTkLabel(popup, text="Enter your API key:")
|
APIlabel = ctk.CTkLabel(popup, text="Enter your API key:")
|
||||||
APIlabel.pack(pady=(15, 5))
|
APIlabel.pack(pady=(15, 5))
|
||||||
|
|
||||||
APIKeyGet = ctk.CTkLabel(popup, text="How to get free API key", text_color="#3366d6", cursor="hand2")
|
APIKeyGet = ctk.CTkLabel(popup, text="How to get free API key", text_color="#3366d6", cursor="hand2", font=("Arial", 12, "underline"))
|
||||||
APIKeyGet.bind("<Button-1>", openWeatherLink)
|
APIKeyGet.bind("<Button-1>", openWeatherLink)
|
||||||
APIKeyGet.pack(pady=5)
|
APIKeyGet.pack(pady=5)
|
||||||
|
|
||||||
@@ -206,6 +257,8 @@ def openAPIPopup():
|
|||||||
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))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def getAPIkey():
|
def getAPIkey():
|
||||||
global APIKey
|
global APIKey
|
||||||
APIKey = APIEntry.get()
|
APIKey = APIEntry.get()
|
||||||
@@ -262,84 +315,44 @@ def openAPIPopup():
|
|||||||
safeAPI = ctk.CTkButton(popup, text="Safe API key", command=getAPIkey)
|
safeAPI = ctk.CTkButton(popup, text="Safe API key", command=getAPIkey)
|
||||||
safeAPI.pack(pady=10)
|
safeAPI.pack(pady=10)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if not APIKey:
|
|
||||||
app.after(500, openAPIPopup)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
searchPage.pack(fill="both", expand=True)
|
|
||||||
searchPage.pack(pady=200)
|
|
||||||
|
|
||||||
searchFrame = ctk.CTkFrame(searchPage, width=500)
|
|
||||||
searchFrame.pack(pady=30, anchor="center")
|
|
||||||
|
|
||||||
searchLabel = ctk.CTkLabel(searchFrame, text="Which city do you want to know the weather?", font=("Arial", 30))
|
|
||||||
searchLabel.pack(pady=5, padx=15)
|
|
||||||
|
|
||||||
cityEntry = ctk.CTkEntry(searchPage, placeholder_text="Enter City", font=("Arial", 22, "bold"), width=800, height=70)
|
|
||||||
cityEntry.pack(pady=10, anchor="center")
|
|
||||||
|
|
||||||
cityEntry.bind("<Return>", lambda event: doSearch())
|
|
||||||
|
|
||||||
resultTitle = ctk.CTkLabel(resultPage, text="Weather: ", font=("Arial", 60, "bold"))
|
|
||||||
resultTitle.pack(pady=20)
|
|
||||||
|
|
||||||
###################################################
|
|
||||||
#### WEATHER FRAMES ####
|
|
||||||
###################################################
|
|
||||||
|
|
||||||
cardsFrame = ctk.CTkFrame(resultPage, fg_color="transparent")
|
|
||||||
cardsFrame.pack(fill="both", expand=True, padx=20, pady=20)
|
|
||||||
|
|
||||||
weatherTempFrame = ctk.CTkFrame(cardsFrame, width=500, height=350)
|
|
||||||
weatherTempFrame.pack(side="left", expand=True, fill="both", padx=10)
|
|
||||||
weatherTempFrame.pack_propagate(False)
|
|
||||||
|
|
||||||
weatherTempTitle = ctk.CTkLabel(weatherTempFrame, text="Temperature", font=("Arial", 45, "bold"))
|
|
||||||
weatherTempTitle.pack(expand=True, fill="both", pady=(20,10))
|
|
||||||
|
|
||||||
weatherTempLabel = ctk.CTkLabel(weatherTempFrame, font=("Arial", 25))
|
|
||||||
weatherTempLabel.pack(expand=True, anchor="n")
|
|
||||||
|
|
||||||
weatherGeneralFrame = ctk.CTkFrame(cardsFrame, width=500, height=350)
|
|
||||||
weatherGeneralFrame.pack(side="left", expand=True, fill="both", padx=10)
|
|
||||||
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.pack(side="left", expand=True, fill="both", padx=10)
|
|
||||||
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 ####
|
|
||||||
##################################################
|
|
||||||
|
|
||||||
returnButton = ctk.CTkButton(resultPage, text="Return", command=returnButtonClick)
|
|
||||||
returnButton.pack(pady=10)
|
|
||||||
|
|
||||||
|
|
||||||
ErrorFrame = ctk.CTkFrame(searchPage)
|
|
||||||
ErrorLabel = ctk.CTkLabel(ErrorFrame, text="")
|
|
||||||
|
|
||||||
def doSearch():
|
def doSearch():
|
||||||
threading.Thread(target=searchWeather, daemon=True).start()
|
threading.Thread(target=searchWeather, daemon=True).start()
|
||||||
|
|
||||||
|
favFrame = ctk.CTkFrame(favPage)
|
||||||
|
favFrame.pack(fill="both", expand=True, pady=10, padx=10)
|
||||||
|
|
||||||
|
def switchFav():
|
||||||
|
resultPage.pack_forget()
|
||||||
|
searchPage.pack_forget()
|
||||||
|
favPage.pack(fill="both", expand=True)
|
||||||
|
|
||||||
|
for widget in favFrame.winfo_children():
|
||||||
|
widget.destroy()
|
||||||
|
|
||||||
|
with open("config/config.json", "r") as file:
|
||||||
|
data = json.load(file)
|
||||||
|
|
||||||
|
favlist = data.get("favourites", [])
|
||||||
|
|
||||||
|
for i, favourite in enumerate(favlist):
|
||||||
|
row = i // 4
|
||||||
|
column = i % 4
|
||||||
|
|
||||||
|
button = ctk.CTkButton(
|
||||||
|
favFrame,
|
||||||
|
text=favourite,
|
||||||
|
height=50,
|
||||||
|
font=("Arial", 20, "bold")
|
||||||
|
)
|
||||||
|
|
||||||
|
button.grid(row=row, column=column, padx=5, pady=5, sticky="ew")
|
||||||
|
|
||||||
|
for column in range(4):
|
||||||
|
favFrame.grid_columnconfigure(column, weight=1)
|
||||||
|
|
||||||
|
|
||||||
def searchWeather():
|
def searchWeather():
|
||||||
|
global city
|
||||||
|
|
||||||
city = cityEntry.get()
|
city = cityEntry.get()
|
||||||
|
|
||||||
@@ -366,8 +379,6 @@ def searchWeather():
|
|||||||
windDirection = data["wind"]["deg"]
|
windDirection = data["wind"]["deg"]
|
||||||
|
|
||||||
|
|
||||||
print(data)
|
|
||||||
|
|
||||||
def show_result():
|
def show_result():
|
||||||
ErrorLabel.configure(text="")
|
ErrorLabel.configure(text="")
|
||||||
ErrorFrame.pack_forget()
|
ErrorFrame.pack_forget()
|
||||||
@@ -389,6 +400,15 @@ def searchWeather():
|
|||||||
)
|
)
|
||||||
searchPage.pack_forget()
|
searchPage.pack_forget()
|
||||||
resultPage.pack(fill="both", expand=True)
|
resultPage.pack(fill="both", expand=True)
|
||||||
|
favouriteCheck.pack(anchor="w", padx=10, pady=5)
|
||||||
|
|
||||||
|
with open("config/config.json", "r") as f:
|
||||||
|
config = json.load(f)
|
||||||
|
|
||||||
|
if city in config.get("favourite", []):
|
||||||
|
favouriteCheck.select()
|
||||||
|
else:
|
||||||
|
favouriteCheck.deselect()
|
||||||
|
|
||||||
app.after(0, show_result)
|
app.after(0, show_result)
|
||||||
|
|
||||||
@@ -433,6 +453,89 @@ def showSearch():
|
|||||||
resultPage.pack(fill="both", expand=True)
|
resultPage.pack(fill="both", expand=True)
|
||||||
|
|
||||||
|
|
||||||
|
if not APIKey:
|
||||||
|
app.after(500, openAPIPopup)
|
||||||
|
|
||||||
|
|
||||||
|
favButton = ctk.CTkButton(app, text="Favourites", height=40, width=200, font=("Arial", 20, "bold"), command=switchFav)
|
||||||
|
favButton.pack(anchor="s", pady=20, padx=20)
|
||||||
|
|
||||||
|
searchPage.pack(fill="both", expand=True)
|
||||||
|
searchPage.pack(pady=200)
|
||||||
|
|
||||||
|
searchFrame = ctk.CTkFrame(searchPage, width=500)
|
||||||
|
searchFrame.pack(pady=(30, 80), anchor="center")
|
||||||
|
|
||||||
|
searchLabel = ctk.CTkLabel(searchFrame, text="From which city do you want to know the weather?", font=("Arial", 30))
|
||||||
|
searchLabel.pack(pady=(5, 5), padx=15)
|
||||||
|
|
||||||
|
cityEntry = ctk.CTkEntry(searchPage, placeholder_text="Enter City", font=("Arial", 22, "bold"), width=800, height=70)
|
||||||
|
cityEntry.pack(pady=10, anchor="center")
|
||||||
|
|
||||||
|
cityEntry.bind("<Return>", lambda event: doSearch())
|
||||||
|
|
||||||
|
favItems = json.load(open("config/config.json", "r"))
|
||||||
|
favlist = favItems.get("favourite")
|
||||||
|
|
||||||
|
favReturnButton = ctk.CTkButton(favPage, text="Return", command=returnButtonClick, width=300, height=50, font=("Arial", 23, "bold"))
|
||||||
|
favReturnButton.pack(pady=10)
|
||||||
|
|
||||||
|
resultTitle = ctk.CTkLabel(resultPage, text="Weather: ", font=("Arial", 60, "bold"))
|
||||||
|
resultTitle.pack(pady=20)
|
||||||
|
|
||||||
|
###################################################
|
||||||
|
#### WEATHER FRAMES ####
|
||||||
|
###################################################
|
||||||
|
|
||||||
|
|
||||||
|
cardsFrame = ctk.CTkFrame(resultPage, fg_color="transparent")
|
||||||
|
cardsFrame.pack(fill="both", expand=True, padx=20, pady=20)
|
||||||
|
|
||||||
|
weatherTempFrame = ctk.CTkFrame(cardsFrame, width=500, height=350)
|
||||||
|
weatherTempFrame.pack(side="left", expand=True, fill="both", padx=10)
|
||||||
|
weatherTempFrame.pack_propagate(False)
|
||||||
|
|
||||||
|
weatherTempTitle = ctk.CTkLabel(weatherTempFrame, text="Temperature", font=("Arial", 45, "bold"))
|
||||||
|
weatherTempTitle.pack(expand=True, fill="both", pady=(20,10))
|
||||||
|
|
||||||
|
weatherTempLabel = ctk.CTkLabel(weatherTempFrame, font=("Arial", 25))
|
||||||
|
weatherTempLabel.pack(expand=True, anchor="n")
|
||||||
|
|
||||||
|
weatherGeneralFrame = ctk.CTkFrame(cardsFrame, width=500, height=350)
|
||||||
|
weatherGeneralFrame.pack(side="left", expand=True, fill="both", padx=10)
|
||||||
|
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.pack(side="left", expand=True, fill="both", padx=10)
|
||||||
|
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 ####
|
||||||
|
##################################################
|
||||||
|
|
||||||
|
searchReturnButton = ctk.CTkButton(resultPage, text="Return", command=returnButtonClick, width=300, height=50, font=("Arial", 23, "bold"))
|
||||||
|
|
||||||
|
searchReturnButton.pack(pady=10)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ErrorFrame = ctk.CTkFrame(searchPage)
|
||||||
|
ErrorLabel = ctk.CTkLabel(ErrorFrame, text="")
|
||||||
|
|
||||||
|
|
||||||
cityEntry.bind("<Return>", lambda event: doSearch())
|
cityEntry.bind("<Return>", lambda event: doSearch())
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user