|
25 | 25 | import subprocess
|
26 | 26 | import sys
|
27 | 27 | import webbrowser
|
| 28 | +import requests |
| 29 | +import babel |
28 | 30 |
|
29 | 31 | MIN_PYTHON = (3, 9)
|
30 | 32 | if sys.version_info < MIN_PYTHON:
|
@@ -554,7 +556,7 @@ def __init__(self, main_window: TuringConfigWindow):
|
554 | 556 | self.window = Toplevel()
|
555 | 557 | self.window.withdraw()
|
556 | 558 | self.window.title('Configure weather & ping')
|
557 |
| - self.window.geometry("750x400") |
| 559 | + self.window.geometry("750x680") |
558 | 560 |
|
559 | 561 | self.main_window = main_window
|
560 | 562 |
|
@@ -614,11 +616,39 @@ def __init__(self, main_window: TuringConfigWindow):
|
614 | 616 | self.lang_cb = ttk.Combobox(self.window, values=list(weather_lang_map.values()), state='readonly')
|
615 | 617 | self.lang_cb.place(x=190, y=325, width=250)
|
616 | 618 |
|
| 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 | + |
617 | 645 | 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) |
619 | 647 |
|
620 | 648 | self.window.protocol("WM_DELETE_WINDOW", self.on_closing)
|
621 | 649 |
|
| 650 | + self._city_entries = [] |
| 651 | + |
622 | 652 | def validateCoord(self, coord: str):
|
623 | 653 | if not coord:
|
624 | 654 | return True
|
@@ -666,6 +696,67 @@ def load_config_values(self, config):
|
666 | 696 | self.lang_cb.set(weather_lang_map[self.config['config']['WEATHER_LANGUAGE']])
|
667 | 697 | except:
|
668 | 698 | 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']}") |
669 | 760 |
|
670 | 761 | def on_save_click(self):
|
671 | 762 | self.save_config_values()
|
|
0 commit comments