Code Sketch
graphic_7325
Category: Art
import javax.swing._
import java.awt._
import java.awt.event._
import java.net.{URL, URLEncoder}
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import scala.io.Source
import scala.util.matching.Regex
// =====================================================
// 1. PASSWORD CHECK (SHA-256)
// =====================================================
def makeHash(text: String): String = {
val md = MessageDigest.getInstance("SHA-256")
val bytes = md.digest(text.getBytes(StandardCharsets.UTF_8))
bytes.map("%02x".format(_)).mkString
}
// Password: weather
val correctPasswordHash =
"4f70104049ebcfe5a3c2205a0df8fd8dd339311dc9fe0b5284710b7a2cee478e"
// =====================================================
// 2. LOGIN SCREEN
// =====================================================
val loginFrame = new JFrame("Weather App - Login")
loginFrame.setSize(450, 280)
loginFrame.setLayout(new BorderLayout())
loginFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)
loginFrame.setLocationRelativeTo(null)
val loginPanel = new JPanel()
loginPanel.setLayout(new GridLayout(5, 1, 8, 8))
val loginTitle = new JLabel("LIVE WEATHER APP", SwingConstants.CENTER)
loginTitle.setFont(new Font("Arial", Font.BOLD, 22))
val passwordLabel = new JLabel("Enter Password (default: weather)", SwingConstants.CENTER)
passwordLabel.setFont(new Font("Arial", Font.PLAIN, 15))
val passwordBox = new JPasswordField()
passwordBox.setFont(new Font("Arial", Font.PLAIN, 18))
val loginButton = new JButton("LOGIN")
loginButton.setFont(new Font("Arial", Font.BOLD, 16))
val loginStatus = new JLabel("", SwingConstants.CENTER)
loginStatus.setForeground(Color.RED)
loginPanel.add(loginTitle)
loginPanel.add(passwordLabel)
loginPanel.add(passwordBox)
loginPanel.add(loginButton)
loginPanel.add(loginStatus)
loginFrame.add(loginPanel, BorderLayout.CENTER)
// =====================================================
// 3. MASTER PRE-DEFINED COORDINATES DATABASE
// =====================================================
val locationMap: Map[String, (String, String, String, String)] = Map(
// ---- 1. ALL INDIA STATES & UNION TERRITORIES ----
"andhra pradesh" -> ("16.5417", "80.5158", "Andhra Pradesh (Amaravati)", "India"),
"arunachal pradesh" -> ("27.1004", "93.6166", "Arunachal Pradesh (Itanagar)", "India"),
"assam" -> ("26.1445", "91.7362", "Assam (Guwahati)", "India"),
"bihar" -> ("25.5941", "85.1376", "Bihar (Patna)", "India"),
"chhattisgarh" -> ("21.2514", "81.6296", "Chhattisgarh (Raipur)", "India"),
"goa" -> ("15.4909", "73.8278", "Goa (Panaji)", "India"),
"gujarat" -> ("23.2156", "72.6369", "Gujarat (Gandhinagar)", "India"),
"haryana" -> ("30.7333", "76.7794", "Haryana (Chandigarh)", "India"),
"himachal pradesh" -> ("31.1048", "77.1734", "Himachal Pradesh (Shimla)", "India"),
"jharkhand" -> ("23.3441", "85.3096", "Jharkhand (Ranchi)", "India"),
"karnataka" -> ("12.9716", "77.5946", "Karnataka (Bengaluru)", "India"),
"kerala" -> ("8.5241", "76.9366", "Kerala (Thiruvananthapuram)", "India"),
"madhya pradesh" -> ("23.2599", "77.4126", "Madhya Pradesh (Bhopal)", "India"),
"maharashtra" -> ("18.9388", "72.8354", "Maharashtra (Mumbai)", "India"),
"manipur" -> ("24.8170", "93.9368", "Manipur (Imphal)", "India"),
"meghalaya" -> ("25.5788", "91.8933", "Meghalaya (Shillong)", "India"),
"mizoram" -> ("23.7271", "92.7176", "Mizoram (Aizawl)", "India"),
"nagaland" -> ("25.6751", "94.1086", "Nagaland (Kohima)", "India"),
"odisha" -> ("20.2961", "85.8245", "Odisha (Bhubaneswar)", "India"),
"punjab" -> ("30.7333", "76.7794", "Punjab (Chandigarh)", "India"),
"rajasthan" -> ("26.9124", "75.7873", "Rajasthan (Jaipur)", "India"),
"sikkim" -> ("27.3389", "88.6065", "Sikkim (Gangtok)", "India"),
"tamil nadu" -> ("13.0827", "80.2707", "Tamil Nadu (Chennai)", "India"),
"telangana" -> ("17.3850", "78.4867", "Telangana (Hyderabad)", "India"),
"tripura" -> ("23.8315", "91.2868", "Tripura (Agartala)", "India"),
"uttar pradesh" -> ("26.8467", "80.9462", "Uttar Pradesh (Lucknow)", "India"),
"uttarakhand" -> ("30.3165", "78.0322", "Uttarakhand (Dehradun)", "India"),
"west bengal" -> ("22.5726", "88.3639", "West Bengal (Kolkata)", "India"),
"delhi" -> ("28.6139", "77.2090", "Delhi (National Capital)", "India"),
"jammu and kashmir" -> ("34.0837", "74.7973", "Jammu & Kashmir (Srinagar)", "India"),
"ladakh" -> ("34.1526", "77.5771", "Ladakh (Leh)", "India"),
"chandigarh" -> ("30.7333", "76.7794", "Chandigarh", "India"),
"puducherry" -> ("11.9416", "79.8083", "Puducherry", "India"),
"andaman and nicobar islands" -> ("11.6234", "92.7265", "Andaman & Nicobar (Port Blair)", "India"),
"dadra and nagar haveli and daman and diu" -> ("20.4283", "72.8397", "Daman and Diu", "India"),
"lakshadweep" -> ("10.5667", "72.6417", "Lakshadweep (Kavaratti)", "India"),
// ---- 2. ALL 36 MAHARASHTRA DISTRICTS ----
"ahmednagar" -> ("19.0952", "74.7496", "Ahilyanagar (Ahmednagar)", "Maharashtra"),
"ahilyanagar" -> ("19.0952", "74.7496", "Ahilyanagar (Ahmednagar)", "Maharashtra"),
"akola" -> ("20.7002", "77.0082", "Akola", "Maharashtra"),
"amravati" -> ("20.9320", "77.7523", "Amravati", "Maharashtra"),
"bhandara" -> ("21.1667", "79.6500", "Bhandara", "Maharashtra"),
"beed" -> ("18.9891", "75.7601", "Beed", "Maharashtra"),
"buldhana" -> ("20.5312", "76.1847", "Buldhana", "Maharashtra"),
"chandrapur" -> ("19.9615", "79.2961", "Chandrapur", "Maharashtra"),
"chhatrapati sambhajinagar" -> ("19.8762", "75.3433", "Chhatrapati Sambhajinagar", "Maharashtra"),
"sambhajinagar" -> ("19.8762", "75.3433", "Chhatrapati Sambhajinagar", "Maharashtra"),
"dharashiv" -> ("18.1853", "76.0419", "Dharashiv (Osmanabad)", "Maharashtra"),
"dhule" -> ("20.9042", "74.7749", "Dhule", "Maharashtra"),
"gadchiroli" -> ("20.1849", "79.9948", "Gadchiroli", "Maharashtra"),
"gondia" -> ("21.4624", "80.1961", "Gondia", "Maharashtra"),
"hingoli" -> ("19.7196", "77.1478", "Hingoli", "Maharashtra"),
"jalgaon" -> ("21.0077", "75.5626", "Jalgaon", "Maharashtra"),
"jalna" -> ("19.8410", "75.8864", "Jalna", "Maharashtra"),
"kolhapur" -> ("16.7050", "74.2433", "Kolhapur", "Maharashtra"),
"latur" -> ("18.4088", "76.5604", "Latur", "Maharashtra"),
"mumbai city" -> ("18.9388", "72.8354", "Mumbai City", "Maharashtra"),
"mumbai suburban" -> ("19.0760", "72.8777", "Mumbai Suburban", "Maharashtra"),
"nagpur" -> ("21.1458", "79.0882", "Nagpur", "Maharashtra"),
"nanded" -> ("19.1383", "77.3210", "Nanded", "Maharashtra"),
"nandurbar" -> ("21.3697", "74.2417", "Nandurbar", "Maharashtra"),
"nashik" -> ("19.9975", "73.7898", "Nashik", "Maharashtra"),
"palghar" -> ("19.6967", "72.7655", "Palghar", "Maharashtra"),
"parbhani" -> ("19.2611", "76.7767", "Parbhani", "Maharashtra"),
"pune" -> ("18.5204", "73.8567", "Pune", "Maharashtra"),
"raigad" -> ("18.6414", "72.8722", "Raigad (Alibag)", "Maharashtra"),
"ratnagiri" -> ("16.9902", "73.3120", "Ratnagiri", "Maharashtra"),
"sangli" -> ("16.8524", "74.5815", "Sangli", "Maharashtra"),
"satara" -> ("17.6805", "74.0183", "Satara", "Maharashtra"),
"sindhudurg" -> ("16.0354", "73.6892", "Sindhudurg (Kudal)", "Maharashtra"),
"solapur" -> ("17.6599", "75.9064", "Solapur", "Maharashtra"),
"thane" -> ("19.2183", "72.9781", "Thane", "Maharashtra"),
"wardha" -> ("20.7453", "78.6022", "Wardha", "Maharashtra"),
"washim" -> ("20.1114", "77.1352", "Washim", "Maharashtra"),
"yavatmal" -> ("20.3888", "78.1204", "Yavatmal", "Maharashtra"),
// ---- 3. PUNE & PCMC (AKURDI & NIGDI ADDED) ----
"akurdi" -> ("18.6475", "73.7711", "Akurdi (PCMC)", "Pune, Maharashtra"),
"nigdi" -> ("18.6544", "73.7661", "Nigdi (PCMC)", "Pune, Maharashtra"),
"bhosari" -> ("18.6275", "73.8447", "Bhosari (PCMC)", "Pune, Maharashtra"),
"pimpri" -> ("18.6298", "73.7997", "Pimpri (PCMC)", "Pune, Maharashtra"),
"chinchwad" -> ("18.6298", "73.7997", "Chinchwad (PCMC)", "Pune, Maharashtra"),
"wakad" -> ("18.5987", "73.7684", "Wakad (PCMC)", "Pune, Maharashtra"),
"hinjawadi" -> ("18.5913", "73.7389", "Hinjawadi IT Park", "Pune, Maharashtra"),
"baner" -> ("18.5590", "73.7868", "Baner", "Pune, Maharashtra"),
"kothrud" -> ("18.5074", "73.8077", "Kothrud", "Pune, Maharashtra"),
"hadapsar" -> ("18.5089", "73.9259", "Hadapsar", "Pune, Maharashtra"),
"katraj" -> ("18.4489", "73.8586", "Katraj", "Pune, Maharashtra"),
"saswad" -> ("18.3439", "74.0294", "Saswad (Purandar)", "Pune, Maharashtra"),
"purandar" -> ("18.3439", "74.0294", "Purandar (Saswad)", "Pune, Maharashtra"),
"jejuri" -> ("18.2766", "74.1593", "Jejuri (Purandar)", "Pune, Maharashtra"),
"bhor" -> ("18.1467", "73.8447", "Bhor", "Pune, Maharashtra"),
"velhe" -> ("18.2970", "73.6358", "Velhe", "Pune, Maharashtra"),
"panshet" -> ("18.3753", "73.6133", "Panshet (Velhe)", "Pune, Maharashtra"),
"baramati" -> ("18.1517", "74.5770", "Baramati", "Pune, Maharashtra"),
"indapur" -> ("18.1147", "75.0292", "Indapur", "Pune, Maharashtra"),
"bhigwan" -> ("18.2917", "74.7708", "Bhigwan (Indapur)", "Pune, Maharashtra"),
"daund" -> ("18.4633", "74.5828", "Daund", "Pune, Maharashtra"),
"shirur" -> ("18.8278", "74.3778", "Shirur", "Pune, Maharashtra"),
"shikrapur" -> ("18.7067", "74.1239", "Shikrapur (Shirur)", "Pune, Maharashtra"),
"junnar" -> ("19.2067", "73.8767", "Junnar", "Pune, Maharashtra"),
"narayangaon" -> ("19.1256", "73.9781", "Narayangaon (Junnar)", "Pune, Maharashtra"),
"otur" -> ("19.2611", "73.9167", "Otur (Junnar)", "Pune, Maharashtra"),
"khed" -> ("18.8500", "73.8833", "Khed (Rajgurunagar)", "Pune, Maharashtra"),
"rajgurunagar" -> ("18.8500", "73.8833", "Rajgurunagar (Khed)", "Pune, Maharashtra"),
"chakan" -> ("18.7606", "73.8576", "Chakan (Khed)", "Pune, Maharashtra"),
"alandi" -> ("18.6775", "73.8967", "Alandi (Khed)", "Pune, Maharashtra"),
"ambegaon" -> ("19.0003", "73.9388", "Ambegaon (Manchar)", "Pune, Maharashtra"),
"manchar" -> ("19.0003", "73.9388", "Manchar (Ambegaon)", "Pune, Maharashtra"),
"ghodegaon" -> ("19.0436", "73.8247", "Ghodegaon (Ambegaon)", "Pune, Maharashtra"),
"maval" -> ("18.7557", "73.4091", "Maval", "Pune, Maharashtra"),
"talegaon dabhade" -> ("18.7342", "73.6761", "Talegaon Dabhade (Maval)", "Pune, Maharashtra"),
"lonavala" -> ("18.7557", "73.4091", "Lonavala (Maval)", "Pune, Maharashtra"),
"khandala" -> ("18.7614", "73.3742", "Khandala (Maval)", "Pune, Maharashtra"),
"dehu" -> ("18.7183", "73.7681", "Dehu (Haveli)", "Pune, Maharashtra"),
"mulshi" -> ("18.5286", "73.5186", "Mulshi (Paud)", "Pune, Maharashtra"),
"paud" -> ("18.5286", "73.6186", "Paud (Mulshi)", "Pune, Maharashtra"),
"pirangut" -> ("18.5122", "73.6811", "Pirangut (Mulshi)", "Pune, Maharashtra"),
"lavasa" -> ("18.4092", "73.5075", "Lavasa (Mulshi)", "Pune, Maharashtra"),
"haveli" -> ("18.5204", "73.8567", "Haveli", "Pune, Maharashtra"),
"khadakwasla" -> ("18.4358", "73.7661", "Khadakwasla (Haveli)", "Pune, Maharashtra"),
"uruli kanchan" -> ("18.4842", "74.1331", "Uruli Kanchan (Haveli)", "Pune, Maharashtra"),
"wagholi" -> ("18.5808", "73.9786", "Wagholi (Haveli)", "Pune, Maharashtra")
)
// =====================================================
// 4. MAIN WEATHER APP
// =====================================================
def startWeatherApp(): Unit = {
loginFrame.setVisible(false)
val frame = new JFrame("Live Weather App - India, Maharashtra, Pune & PCMC")
frame.setSize(1120, 760)
frame.setLayout(new BorderLayout())
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)
frame.setLocationRelativeTo(null)
val mainTopPanel = new JPanel()
mainTopPanel.setLayout(new BoxLayout(mainTopPanel, BoxLayout.Y_AXIS))
val searchInputPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 8))
val cityBox = new JTextField(22)
cityBox.setFont(new Font("Arial", Font.PLAIN, 16))
val searchButton = new JButton("SEARCH WEATHER")
searchButton.setFont(new Font("Arial", Font.BOLD, 14))
val logoutButton = new JButton("LOGOUT")
logoutButton.setFont(new Font("Arial", Font.BOLD, 13))
logoutButton.setBackground(new Color(220, 53, 69))
logoutButton.setForeground(Color.WHITE)
logoutButton.setFocusPainted(false)
searchInputPanel.add(new JLabel("Search Location:"))
searchInputPanel.add(cityBox)
searchInputPanel.add(searchButton)
searchInputPanel.add(logoutButton)
// ---------------------------------------------------
// DROPDOWNS
// ---------------------------------------------------
val allIndiaStates = Array(
"-- Select India State / UT --",
"Andhra Pradesh", "Arunachal Pradesh", "Assam", "Bihar", "Chhattisgarh",
"Goa", "Gujarat", "Haryana", "Himachal Pradesh", "Jharkhand", "Karnataka",
"Kerala", "Madhya Pradesh", "Maharashtra", "Manipur", "Meghalaya", "Mizoram",
"Nagaland", "Odisha", "Punjab", "Rajasthan", "Sikkim", "Tamil Nadu",
"Telangana", "Tripura", "Uttar Pradesh", "Uttarakhand", "West Bengal",
"Delhi", "Jammu and Kashmir", "Ladakh", "Chandigarh", "Puducherry",
"Andaman and Nicobar Islands", "Dadra and Nagar Haveli and Daman and Diu", "Lakshadweep"
)
val maharashtraDistricts = Array(
"-- Select Maharashtra District --",
"Ahmednagar", "Akola", "Amravati", "Bhandara", "Beed", "Buldhana",
"Chandrapur", "Chhatrapati Sambhajinagar", "Dharashiv", "Dhule",
"Gadchiroli", "Gondia", "Hingoli", "Jalgaon", "Jalna", "Kolhapur",
"Latur", "Mumbai City", "Mumbai Suburban", "Nagpur", "Nanded",
"Nandurbar", "Nashik", "Palghar", "Parbhani", "Pune", "Raigad",
"Ratnagiri", "Sangli", "Satara", "Sindhudurg", "Solapur", "Thane",
"Wardha", "Washim", "Yavatmal"
)
val puneLocations = Array(
"-- Select Pune & PCMC Area --",
"Akurdi", "Nigdi", "Pimpri", "Chinchwad", "Bhosari", "Wakad", "Hinjawadi",
"Saswad", "Purandar", "Jejuri", "Bhor", "Velhe", "Panshet",
"Pune", "Kothrud", "Hadapsar", "Katraj", "Baner", "Haveli", "Khadakwasla",
"Uruli Kanchan", "Wagholi", "Baramati", "Shirur", "Shikrapur", "Junnar",
"Narayangaon", "Otur", "Khed", "Rajgurunagar", "Chakan", "Alandi",
"Ambegaon", "Manchar", "Ghodegaon", "Maval", "Talegaon Dabhade", "Lonavala",
"Khandala", "Dehu", "Mulshi", "Paud", "Pirangut", "Lavasa", "Daund", "Indapur", "Bhigwan"
)
val indiaDropdown = new JComboBox[String](allIndiaStates)
val mahaDropdown = new JComboBox[String](maharashtraDistricts)
val puneDropdown = new JComboBox[String](puneLocations)
val quickSelectPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 8, 6))
quickSelectPanel.add(new JLabel("India States:"))
quickSelectPanel.add(indiaDropdown)
quickSelectPanel.add(new JLabel("Maharashtra (36 Districts):"))
quickSelectPanel.add(mahaDropdown)
quickSelectPanel.add(new JLabel("Pune & PCMC (Akurdi, Nigdi...):"))
quickSelectPanel.add(puneDropdown)
mainTopPanel.add(searchInputPanel)
mainTopPanel.add(quickSelectPanel)
val result = new JTextArea()
result.setFont(new Font("Monospaced", Font.PLAIN, 16))
result.setEditable(false)
result.setMargin(new Insets(12, 12, 12, 12))
val scroll = new JScrollPane(result)
val historyPanel = new JPanel(new BorderLayout())
val historyTitle = new JLabel("SEARCH HISTORY", SwingConstants.CENTER)
historyTitle.setFont(new Font("Arial", Font.BOLD, 14))
val historyList = new DefaultListModel[String]()
val history = new JList[String](historyList)
history.setFont(new Font("Arial", Font.PLAIN, 14))
val clearHistoryButton = new JButton("CLEAR HISTORY")
historyPanel.add(historyTitle, BorderLayout.NORTH)
historyPanel.add(new JScrollPane(history), BorderLayout.CENTER)
historyPanel.add(clearHistoryButton, BorderLayout.SOUTH)
historyPanel.setPreferredSize(new Dimension(210, 0))
val status = new JLabel(" Ready. Akurdi, Nigdi, PCMC, Pune & Maharashtra districts loaded.", SwingConstants.LEFT)
status.setFont(new Font("Arial", Font.PLAIN, 14))
frame.add(mainTopPanel, BorderLayout.NORTH)
frame.add(scroll, BorderLayout.CENTER)
frame.add(historyPanel, BorderLayout.EAST)
frame.add(status, BorderLayout.SOUTH)
// ---------------------------------------------------
// JSON Helpers
// ---------------------------------------------------
def getNumber(json: String, key: String): String = {
val pattern = ("\"" + Regex.quote(key) + "\"\\s*:\\s*(-?[0-9]+(?:\\.[0-9]+)?)").r
pattern.findFirstMatchIn(json) match {
case Some(m) => m.group(1)
case None => "0.0"
}
}
def getString(json: String, key: String): String = {
val pattern = ("\"" + Regex.quote(key) + "\"\\s*:\\s*\"([^\"]*)\"").r
pattern.findFirstMatchIn(json) match {
case Some(m) => m.group(1)
case None => "N/A"
}
}
def weatherCondition(code: String): (String, String) = {
code match {
case "0" => ("[SUN]", "Clear Sky (?????? ??)")
case "1" | "2" => ("[PARTLY CLOUDY]", "Partly Cloudy (????? ????)")
case "3" => ("[CLOUD]", "Overcast / Cloudy (????)")
case "45" | "48" => ("[FOG]", "Foggy (????)")
case "51" | "53" | "55" => ("[DRIZZLE]", "Drizzle (?????? ????)")
case "61" | "63" | "65" => ("[RAIN]", "Rain (????)")
case "71" | "73" | "75" => ("[SNOW]", "Snow (??????????)")
case "80" | "81" | "82" => ("[SHOWERS]", "Rain Showers (??????? ???)")
case "95" => ("[STORM]", "Thunderstorm (????? ????)")
case "96" | "99" => ("[HAIL]", "Hailstorm (??????)")
case _ => ("[WEATHER]", "Normal / Moderate")
}
}
def fetchOnlineCoordinates(query: String): (String, String, String, String) = {
try {
val encoded = URLEncoder.encode(query, StandardCharsets.UTF_8.toString)
val url = s"https://geocoding-api.open-meteo.com/v1/search?name=$encoded&count=1&language=en&format=json&countryCode=IN"
val source = Source.fromURL(new URL(url), "UTF-8")
val json = try source.mkString finally source.close()
val lat = getNumber(json, "latitude")
val lon = getNumber(json, "longitude")
val name = getString(json, "name")
val admin = getString(json, "admin1")
if (lat == "0.0" || lon == "0.0") ("N/A", "N/A", "N/A", "N/A")
else (lat, lon, name, admin)
} catch {
case _: Exception => ("N/A", "N/A", "N/A", "N/A")
}
}
// ---------------------------------------------------
// SEARCH ENGINE
// ---------------------------------------------------
def searchWeather(targetPlace: String): Unit = {
val raw = targetPlace.trim
if (raw.isEmpty || raw.startsWith("--")) {
JOptionPane.showMessageDialog(frame, "Please enter or select a valid place.", "Input Required", JOptionPane.WARNING_MESSAGE)
return
}
result.setText(s"Searching weather details for '$raw'...")
status.setText(s"Fetching live data for $raw...")
searchButton.setEnabled(false)
val worker = new Thread(new Runnable {
override def run(): Unit = {
try {
val cleanKey = raw.toLowerCase.trim
var lat = "N/A"
var lon = "N/A"
var displayName = raw
var regionName = "India"
// 1. ??? ????-??????? ??????????? ?????
if (locationMap.contains(cleanKey)) {
val data = locationMap(cleanKey)
lat = data._1
lon = data._2
displayName = data._3
regionName = data._4
} else {
// 2. ?????? ?????
var online = fetchOnlineCoordinates(raw)
if (online._1 == "N/A") online = fetchOnlineCoordinates(s"$raw, PCMC")
if (online._1 == "N/A") online = fetchOnlineCoordinates(s"$raw, Pune")
if (online._1 == "N/A") online = fetchOnlineCoordinates(s"$raw, Maharashtra")
if (online._1 != "N/A") {
lat = online._1
lon = online._2
displayName = s"$raw (${online._3})"
regionName = if (online._4 != "N/A") s"${online._4}, India" else "India"
}
}
if (lat == "N/A" || lon == "N/A") {
SwingUtilities.invokeLater(new Runnable {
override def run(): Unit = {
result.setText(
s"LOCATION NOT FOUND: '$raw'\n\n" +
"Please choose directly from the dropdowns above."
)
status.setText("Location not found")
searchButton.setEnabled(true)
}
})
return
}
// 3. ?????? ?????? API ???? ???? ??????
val weatherUrl = s"https://api.open-meteo.com/v1/forecast?latitude=$lat&longitude=$lon¤t=temperature_2m,relative_humidity_2m,rain,weather_code,wind_speed_10m&temperature_unit=celsius&wind_speed_unit=kmh&timezone=auto"
val weatherSource = Source.fromURL(new URL(weatherUrl), "UTF-8")
val weatherJson = try weatherSource.mkString finally weatherSource.close()
val temp = getNumber(weatherJson, "temperature_2m")
val humidity = getNumber(weatherJson, "relative_humidity_2m")
val rain = getNumber(weatherJson, "rain")
val wind = getNumber(weatherJson, "wind_speed_10m")
val code = getNumber(weatherJson, "weather_code")
val time = getString(weatherJson, "time")
val (symbol, condition) = weatherCondition(code)
SwingUtilities.invokeLater(new Runnable {
override def run(): Unit = {
if (!historyList.contains(displayName)) {
historyList.addElement(displayName)
}
val report =
s"""=====================================================
| LIVE WEATHER REPORT
|=====================================================
| Status : $symbol $condition
| Location : $displayName
| State/Region : $regionName
| Coordinates : Lat $lat, Lon $lon
|-----------------------------------------------------
| Temperature : $temp �C
| Humidity : $humidity %
| Rain : $rain mm
| Wind Speed : $wind km/h
|-----------------------------------------------------
| Last Updated : $time
| Live API : Open-Meteo Weather Service
|=====================================================""".stripMargin
result.setText(report)
status.setText(s"Weather loaded successfully for $displayName")
searchButton.setEnabled(true)
}
})
} catch {
case _: Exception =>
SwingUtilities.invokeLater(new Runnable {
override def run(): Unit = {
result.setText("INTERNET / SERVER ERROR\n\nPlease check your internet connection and try again.")
status.setText("Network error")
searchButton.setEnabled(true)
}
})
}
}
})
worker.start()
}
// ---------------------------------------------------
// LOGOUT ACTION
// ---------------------------------------------------
logoutButton.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = {
val confirm = JOptionPane.showConfirmDialog(
frame,
"Are you sure you want to logout?",
"Confirm Logout",
JOptionPane.YES_NO_OPTION
)
if (confirm == JOptionPane.YES_OPTION) {
frame.dispose()
passwordBox.setText("")
loginStatus.setText("Logged out successfully!")
loginStatus.setForeground(new Color(0, 128, 0))
loginFrame.setVisible(true)
passwordBox.requestFocus()
}
}
})
// ---------------------------------------------------
// LISTENERS
// ---------------------------------------------------
searchButton.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = searchWeather(cityBox.getText)
})
cityBox.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = searchWeather(cityBox.getText)
})
indiaDropdown.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = {
val item = indiaDropdown.getSelectedItem.toString
if (!item.startsWith("--")) {
cityBox.setText(item)
searchWeather(item)
}
}
})
mahaDropdown.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = {
val item = mahaDropdown.getSelectedItem.toString
if (!item.startsWith("--")) {
cityBox.setText(item)
searchWeather(item)
}
}
})
puneDropdown.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = {
val item = puneDropdown.getSelectedItem.toString
if (!item.startsWith("--")) {
cityBox.setText(item)
searchWeather(item)
}
}
})
history.addMouseListener(new MouseAdapter {
override def mouseClicked(e: MouseEvent): Unit = {
val item = history.getSelectedValue
if (item != null && !item.isEmpty) {
val cleanName = item.split("\\(")(0).trim
cityBox.setText(cleanName)
searchWeather(cleanName)
}
}
})
clearHistoryButton.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = {
historyList.clear()
status.setText("History cleared")
}
})
frame.setVisible(true)
cityBox.requestFocus()
}
// =====================================================
// 5. LOGIN ACTIONS
// =====================================================
def checkPassword(): Unit = {
val entered = new String(passwordBox.getPassword)
if (makeHash(entered) == correctPasswordHash) {
loginStatus.setText("")
startWeatherApp()
} else {
loginStatus.setForeground(Color.RED)
loginStatus.setText("Wrong password! Default is: weather")
passwordBox.setText("")
}
}
loginButton.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = checkPassword()
})
passwordBox.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = checkPassword()
})
loginFrame.setVisible(true)
passwordBox.requestFocus()