mumok4 пре 4 недеља
родитељ
комит
79424a291f

+ 47 - 24
weather/app/src/main/java/com/example/weather/MainActivity.kt

@@ -3,6 +3,7 @@ package com.example.weather
 import android.os.Bundle
 import android.util.Log
 import android.view.View
+import android.widget.AdapterView
 import android.widget.ImageView
 import android.widget.Toast
 import androidx.appcompat.app.AppCompatActivity
@@ -16,51 +17,61 @@ import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import org.json.JSONObject
 import java.net.URL
+import kotlin.math.roundToInt
 
-// === 1. Основная Activity ===
 class MainActivity : AppCompatActivity() {
 
     private lateinit var binding: ActivityMainBinding
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-        // Инициализация Binding
         binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
 
-        // Начальное состояние
         binding.isLoading = false
+        binding.isFahrenheit = false
+        binding.showWind = true
+
+        setupListeners()
     }
 
-    // Метод клика (вызывается из XML)
-    fun onGetWeatherClick(view: View) {
-        val city = binding.etCity.text.toString().trim()
-        if (city.isNotEmpty()) loadWeather(city)
-        else Toast.makeText(this, "Введите город", Toast.LENGTH_SHORT).show()
+    private fun setupListeners() {
+        binding.spinnerCity.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
+            override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
+                val city = parent?.getItemAtPosition(position).toString()
+                loadWeather(city)
+            }
+            override fun onNothingSelected(parent: AdapterView<*>?) {}
+        }
+
+        binding.rgTemp.setOnCheckedChangeListener { _, checkedId ->
+            binding.isFahrenheit = (checkedId == R.id.rbFahrenheit)
+        }
+
+        binding.cbWind.setOnCheckedChangeListener { _, isChecked ->
+            binding.showWind = isChecked
+        }
     }
 
     private fun loadWeather(city: String) {
-        binding.isLoading = true // Покажется ProgressBar (см. XML)
+        binding.isLoading = true
 
         lifecycleScope.launch(Dispatchers.IO) {
             try {
-                // Вставьте свой API ключ сюда или в strings.xml
                 val apiKey = getString(R.string.open_weather_map_key)
                 val url = "https://api.openweathermap.org/data/2.5/weather?q=$city&appid=$apiKey&units=metric"
 
-                // Загрузка и парсинг
                 val jsonString = URL(url).readText()
                 val weatherData = parseWeatherData(jsonString)
 
-                // Обновление UI
                 withContext(Dispatchers.Main) {
-                    binding.weather = weatherData // Вся магия DataBinding здесь
+                    binding.weather = weatherData
                     binding.isLoading = false
                 }
             } catch (e: Exception) {
-                Log.e("Weather", "Error", e)
+                Log.e("WeatherApp", "Error", e)
                 withContext(Dispatchers.Main) {
                     binding.isLoading = false
-                    Toast.makeText(this@MainActivity, "Ошибка: ${e.message}", Toast.LENGTH_LONG).show()
+                    Toast.makeText(this@MainActivity, "Ошибка: ${e.message}", Toast.LENGTH_SHORT).show()
                 }
             }
         }
@@ -73,31 +84,43 @@ class MainActivity : AppCompatActivity() {
         val wind = json.getJSONObject("wind")
 
         return WeatherInfo(
-            temperature = "${main.getDouble("temp").toInt()}°C",
+            tempVal = main.getDouble("temp"),
             description = weatherObj.getString("description").replaceFirstChar { it.uppercase() },
             iconUrl = "https://openweathermap.org/img/wn/${weatherObj.getString("icon")}@4x.png",
-            windInfo = "Wind: ${wind.getDouble("speed")} m/s",
+            windSpeed = wind.getDouble("speed"),
             windRotation = wind.optDouble("deg", 0.0).toFloat() + 180f,
             humidity = "Humidity: ${main.getInt("humidity")}%"
         )
     }
 }
 
-// === 2. Модель данных (Data Class) ===
+// === Модель данных ===
 data class WeatherInfo(
-    val temperature: String,
+    val tempVal: Double,
     val description: String,
     val iconUrl: String,
-    val windInfo: String,
+    val windSpeed: Double,
     val windRotation: Float,
     val humidity: String
-)
+) {
+    // Вспомогательная функция для Data Binding
+    // Вызывается из XML как @{weather.getTempString(isFahrenheit)}
+    fun getTempString(isFahrenheit: Boolean): String {
+        return if (isFahrenheit) {
+            val f = (tempVal * 1.8) + 32
+            "${f.roundToInt()}°F"
+        } else {
+            "${tempVal.roundToInt()}°C"
+        }
+    }
+}
 
-// === 3. Адаптеры (Binding Adapters) ===
-// Функции верхнего уровня, чтобы DataBinding их видел
+// === Binding Adapters ===
 @BindingAdapter("app:imageUrl")
 fun loadImage(view: ImageView, url: String?) {
-    if (!url.isNullOrEmpty()) Picasso.get().load(url).into(view)
+    if (!url.isNullOrEmpty()) {
+        Picasso.get().load(url).into(view)
+    }
 }
 
 @BindingAdapter("app:rotationAngle")

+ 70 - 29
weather/app/src/main/res/layout/activity_main.xml

@@ -5,9 +5,13 @@
 
     <data>
         <import type="android.view.View"/>
-        <!-- Ссылка на наш Data Class внизу файла MainActivity.kt -->
+
         <variable name="weather" type="com.example.weather.WeatherInfo" />
         <variable name="isLoading" type="Boolean" />
+
+        <!-- Переменные состояния -->
+        <variable name="isFahrenheit" type="Boolean" />
+        <variable name="showWind" type="Boolean" />
     </data>
 
     <androidx.constraintlayout.widget.ConstraintLayout
@@ -15,26 +19,59 @@
         android:layout_height="match_parent"
         android:padding="16dp">
 
-        <EditText
-            android:id="@+id/etCity"
+        <Spinner
+            android:id="@+id/spinnerCity"
             android:layout_width="0dp"
             android:layout_height="wrap_content"
-            android:hint="City (e.g. Paris)"
-            android:text="London"
-            app:layout_constraintEnd_toStartOf="@+id/btnSearch"
+            android:entries="@array/cities_array"
+            android:minHeight="48dp"
+            app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toTopOf="parent" />
 
-        <Button
-            android:id="@+id/btnSearch"
-            android:layout_width="wrap_content"
+        <LinearLayout
+            android:id="@+id/settingsPanel"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:text="Search"
-            android:onClick="onGetWeatherClick"
-            app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintTop_toTopOf="parent" />
+            android:orientation="horizontal"
+            android:gravity="center_vertical"
+            android:layout_marginTop="10dp"
+            app:layout_constraintTop_toBottomOf="@+id/spinnerCity">
+
+            <RadioGroup
+                android:id="@+id/rgTemp"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal">
+
+                <RadioButton
+                    android:id="@+id/rbCelsius"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="°C"
+                    android:checked="true"/>
+
+                <RadioButton
+                    android:id="@+id/rbFahrenheit"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="°F"
+                    android:layout_marginStart="8dp"/>
+            </RadioGroup>
+
+            <View
+                android:layout_width="0dp"
+                android:layout_height="0dp"
+                android:layout_weight="1"/>
+
+            <CheckBox
+                android:id="@+id/cbWind"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Wind Info"
+                android:checked="true"/>
+        </LinearLayout>
 
-        <!-- Прогресс бар, виден если isLoading == true -->
         <ProgressBar
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -42,25 +79,26 @@
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@+id/etCity" />
+            app:layout_constraintTop_toBottomOf="@+id/settingsPanel" />
 
-        <!-- Контейнер погоды, виден если данные есть и не грузимся -->
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:orientation="vertical"
             android:gravity="center"
             android:visibility="@{!isLoading &amp;&amp; weather != null ? View.VISIBLE : View.GONE}"
-            app:layout_constraintTop_toBottomOf="@+id/etCity"
+            app:layout_constraintTop_toBottomOf="@+id/settingsPanel"
             app:layout_constraintBottom_toBottomOf="parent">
 
+            <!-- ИСПРАВЛЕНИЕ ЗДЕСЬ: Вызов метода модели вместо сложной логики в XML -->
             <TextView
-                android:text="@{weather.temperature}"
-                android:textSize="60sp"
+                android:text="@{weather.getTempString(isFahrenheit)}"
+                android:textSize="80sp"
                 android:textStyle="bold"
+                android:textColor="@android:color/holo_blue_dark"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                tools:text="20°C"/>
+                tools:text="25°C"/>
 
             <ImageView
                 android:layout_width="120dp"
@@ -71,33 +109,37 @@
             <TextView
                 android:text="@{weather.description}"
                 android:textSize="24sp"
+                android:textAllCaps="true"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                tools:text="Sunny"/>
+                tools:text="Clear Sky"/>
 
             <TextView
                 android:text="@{weather.humidity}"
-                android:layout_marginTop="10dp"
+                android:layout_marginTop="8dp"
                 android:layout_width="wrap_content"
-                android:layout_height="wrap_content"/>
+                android:layout_height="wrap_content"
+                tools:text="Humidity: 50%"/>
 
             <LinearLayout
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:orientation="horizontal"
                 android:gravity="center_vertical"
-                android:layout_marginTop="10dp">
+                android:layout_marginTop="16dp"
+                android:visibility="@{showWind ? View.VISIBLE : View.GONE}">
 
+                <!-- Простое объединение строк работает стабильнее -->
                 <TextView
-                    android:text="@{weather.windInfo}"
+                    android:text="@{`Wind: ` + weather.windSpeed + ` m/s`}"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
+                    android:textSize="16sp"
                     tools:text="Wind: 5 m/s"/>
 
-                <!-- Стрелка ветра -->
                 <ImageView
-                    android:layout_width="30dp"
-                    android:layout_height="30dp"
+                    android:layout_width="24dp"
+                    android:layout_height="24dp"
                     android:src="@android:drawable/arrow_up_float"
                     app:tint="#555"
                     app:rotationAngle="@{weather.windRotation}"
@@ -105,6 +147,5 @@
             </LinearLayout>
 
         </LinearLayout>
-
     </androidx.constraintlayout.widget.ConstraintLayout>
 </layout>

+ 12 - 1
weather/app/src/main/res/values/strings.xml

@@ -1,4 +1,15 @@
 <resources>
-    <string name="app_name">weather</string>
+    <string name="app_name">WeatherApp</string>
+    <!-- Ваш ключ -->
     <string name="open_weather_map_key">d6843ab8ee963f5d372296dfff62aed7</string>
+
+    <!-- Список городов для Spinner -->
+    <string-array name="cities_array">
+        <item>Moscow</item>
+        <item>London</item>
+        <item>New York</item>
+        <item>Tokyo</item>
+        <item>Paris</item>
+        <item>Berlin</item>
+    </string-array>
 </resources>