Skip to content

Commit e8f7d1e

Browse files
authored
Merge pull request #823 from rud01f/feature/search-and-autofill-city-lat-long-with-geoapi
2 parents fd7bfb2 + ae4267a commit e8f7d1e

File tree

1 file changed

+93
-2
lines changed

1 file changed

+93
-2
lines changed

configure.py

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import subprocess
2626
import sys
2727
import webbrowser
28+
import requests
29+
import babel
2830

2931
MIN_PYTHON = (3, 9)
3032
if sys.version_info < MIN_PYTHON:
@@ -554,7 +556,7 @@ def __init__(self, main_window: TuringConfigWindow):
554556
self.window = Toplevel()
555557
self.window.withdraw()
556558
self.window.title('Configure weather & ping')
557-
self.window.geometry("750x400")
559+
self.window.geometry("750x680")
558560

559561
self.main_window = main_window
560562

@@ -614,11 +616,39 @@ def __init__(self, main_window: TuringConfigWindow):
614616
self.lang_cb = ttk.Combobox(self.window, values=list(weather_lang_map.values()), state='readonly')
615617
self.lang_cb.place(x=190, y=325, width=250)
616618

619+
self.citysearch1_label = ttk.Label(self.window, text='Location search', font='bold')
620+
self.citysearch1_label.place(x=80, y=370)
621+
622+
self.citysearch2_label = ttk.Label(self.window, text="Enter location to automatically get coordinates (latitude/longitude).\n"
623+
"For example \"Berlin\" \"London, GB\", \"London, Quebec\".\n"
624+
"Remember to set valid API key and pick language first!")
625+
self.citysearch2_label.place(x=10, y=396)
626+
627+
self.citysearch3_label = ttk.Label(self.window, text="Enter location")
628+
self.citysearch3_label.place(x=10, y=474)
629+
self.citysearch_entry = ttk.Entry(self.window)
630+
self.citysearch_entry.place(x=140, y=470, width=300)
631+
self.citysearch_btn = ttk.Button(self.window, text="Search", command=lambda: self.on_search_click())
632+
self.citysearch_btn.place(x=450, y=468, height=40, width=130)
633+
634+
self.citysearch4_label = ttk.Label(self.window, text="Select location\n(use after Search)")
635+
self.citysearch4_label.place(x=10, y=540)
636+
self.citysearch_cb = ttk.Combobox(self.window, values=[], state='readonly')
637+
self.citysearch_cb.place(x=140, y=544, width=360)
638+
self.citysearch_btn2 = ttk.Button(self.window, text="Fill in lat/long", command=lambda: self.on_filllatlong_click())
639+
self.citysearch_btn2.place(x=520, y=540, height=40, width=130)
640+
641+
self.citysearch_warn_label = ttk.Label(self.window, text="")
642+
self.citysearch_warn_label.place(x=20, y=600)
643+
self.citysearch_warn_label.config(foreground="#ff0000")
644+
617645
self.save_btn = ttk.Button(self.window, text="Save settings", command=lambda: self.on_save_click())
618-
self.save_btn.place(x=590, y=340, height=50, width=130)
646+
self.save_btn.place(x=590, y=620, height=50, width=130)
619647

620648
self.window.protocol("WM_DELETE_WINDOW", self.on_closing)
621649

650+
self._city_entries = []
651+
622652
def validateCoord(self, coord: str):
623653
if not coord:
624654
return True
@@ -666,6 +696,67 @@ def load_config_values(self, config):
666696
self.lang_cb.set(weather_lang_map[self.config['config']['WEATHER_LANGUAGE']])
667697
except:
668698
self.lang_cb.set(weather_lang_map["en"])
699+
700+
def citysearch_show_warning(self, warning):
701+
self.citysearch_warn_label.config(text=warning)
702+
703+
def on_search_click(self):
704+
OPENWEATHER_GEOAPI_URL = "http://api.openweathermap.org/geo/1.0/direct"
705+
api_key = self.api_entry.get()
706+
lang = [k for k, v in weather_lang_map.items() if v == self.lang_cb.get()][0]
707+
city = self.citysearch_entry.get()
708+
709+
if len(api_key) == 0 or len(city) == 0:
710+
self.citysearch_show_warning("API key and city name cannot be empty.")
711+
return
712+
713+
try:
714+
request = requests.get(OPENWEATHER_GEOAPI_URL, timeout=5, params={"appid": api_key, "lang": lang,
715+
"q": city, "limit": 10})
716+
except:
717+
self.citysearch_show_warning("Error fetching OpenWeatherMap Geo API")
718+
return
719+
720+
if request.status_code == 401:
721+
self.citysearch_show_warning("Invalid OpenWeatherMap API key.")
722+
return
723+
elif request.status_code != 200:
724+
self.citysearch_show_warning(f"Error #{request.status_code} fetching OpenWeatherMap Geo API.")
725+
return
726+
727+
self._city_entries = []
728+
cb_entries = []
729+
for entry in request.json():
730+
name = entry['name']
731+
state = entry.get('state', None)
732+
lat = entry['lat']
733+
long = entry['lon']
734+
country_code = entry['country'].upper()
735+
country = babel.Locale(lang).territories[country_code]
736+
if state is not None:
737+
full_name = f"{name}, {state}, {country}"
738+
else:
739+
full_name = f"{name}, {country}"
740+
self._city_entries.append({"full_name": full_name, "lat": str(lat), "long": str(long)})
741+
cb_entries.append(full_name)
742+
743+
self.citysearch_cb.config(values = cb_entries)
744+
if len(cb_entries) == 0:
745+
self.citysearch_show_warning("No given city found.")
746+
else:
747+
self.citysearch_cb.current(0)
748+
self.citysearch_show_warning("Select your city now from list and apply \"Fill in lat/long\".")
749+
750+
def on_filllatlong_click(self):
751+
if len(self._city_entries) == 0:
752+
self.citysearch_show_warning("No city selected or no search results.")
753+
return
754+
city = [i for i in self._city_entries if i['full_name'] == self.citysearch_cb.get()][0]
755+
self.lat_entry.delete(0, END)
756+
self.lat_entry.insert(0, city['lat'])
757+
self.long_entry.delete(0, END)
758+
self.long_entry.insert(0, city['long'])
759+
self.citysearch_show_warning(f"Lat/long values filled for {city['full_name']}")
669760

670761
def on_save_click(self):
671762
self.save_config_values()

0 commit comments

Comments
 (0)