This commit is contained in:
SKILLISSUE1 2026-01-12 20:11:57 +07:00
parent 5a50960c68
commit 4fcdd3ca2b
42 changed files with 801 additions and 341 deletions

View File

@ -4,14 +4,6 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-12-18T06:25:18.162928Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=325F50919896" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
</selectionStates>
</component>

1
.idea/misc.xml generated
View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">

View File

@ -6,11 +6,12 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@drawable/ic_launcher_foreground"
android:roundIcon="@drawable/ic_launcher_foreground"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.WeatherDemo"
@ -33,7 +34,10 @@
<!-- WAJIB: ChatActivity -->
<activity
android:name=".ui.ChatActivity"
android:exported="true" />
android:theme="@style/Theme.WeatherDemo.NoActionBar"
android:windowSoftInputMode="adjustResize|stateHidden"/>
</application>

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

View File

@ -1,22 +1,19 @@
package com.example.weatherdemo.data.api
import com.example.weatherdemo.data.models.WeatherForecastResponse
import com.example.weatherdemo.data.models.WeatherResponse
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Query
import retrofit2.Response
/**
* Retrofit service interface for Weather API
* Retrofit service interface for Weather API (WeatherAPI.com)
* Defines the API endpoints and request methods
*/
interface WeatherApiService {
/**
* Fetches current weather data for a specific location
* @param key API key for authentication
* @param query Location query (city name, zip code, etc.)
* @param aqi Whether to include air quality index (yes/no)
*/
@GET("current.json")
suspend fun getCurrentWeather(
@ -24,4 +21,17 @@ interface WeatherApiService {
@Query("q") query: String,
@Query("aqi") aqi: String = "yes"
): Response<WeatherResponse>
/**
* Fetches forecast (current + hourly + daily) for a specific location
* @param days number of days forecast
*/
@GET("forecast.json")
suspend fun getForecastWeather(
@Query("key") key: String,
@Query("q") query: String,
@Query("days") days: Int = 3,
@Query("aqi") aqi: String = "no",
@Query("alerts") alerts: String = "no"
): Response<WeatherForecastResponse>
}

View File

@ -0,0 +1,36 @@
package com.example.weatherdemo.data.models
/**
* Response model for WeatherAPI "forecast.json".
* This includes current weather + hourly & daily forecast.
*/
data class WeatherForecastResponse(
val location: Location,
val current: Current,
val forecast: Forecast
)
data class Forecast(
val forecastday: List<ForecastDay>
)
data class ForecastDay(
val date: String,
val day: Day,
val hour: List<Hour>
)
data class Day(
val maxtemp_c: Double,
val mintemp_c: Double,
val avgtemp_c: Double,
val condition: Condition,
val daily_chance_of_rain: Int? = null
)
data class Hour(
val time: String,
val temp_c: Double,
val condition: Condition,
val chance_of_rain: Int? = null
)

View File

@ -1,7 +1,7 @@
package com.example.weatherdemo.data.repository
import com.example.weatherdemo.data.api.WeatherApiService
import com.example.weatherdemo.data.models.WeatherResponse
import com.example.weatherdemo.data.models.WeatherForecastResponse
import com.example.weatherdemo.utils.Result
import retrofit2.Response
@ -12,23 +12,24 @@ import retrofit2.Response
class WeatherRepository(private val apiService: WeatherApiService) {
/**
* Fetches weather data from API and returns a Result wrapper
* @param location The location to get weather for
* @return Result object containing either success or error
* Fetches forecast weather data from API and returns a Result wrapper.
* This uses WeatherAPI "forecast.json" so we can show hourly/daily prediction on main page.
*
* @param location The location to get weather for (city name, zip, lat/long)
* @param days number of forecast days (default 3)
*/
suspend fun getWeatherData(location: String): Result<WeatherResponse> {
suspend fun getWeatherForecast(location: String, days: Int = 3): Result<WeatherForecastResponse> {
return try {
// Make API call
val response: Response<WeatherResponse> = apiService.getCurrentWeather(
val response: Response<WeatherForecastResponse> = apiService.getForecastWeather(
key = "822615b3cef1437bb0202739251712", // API key
query = location
query = location,
days = days
)
// Check if response is successful
if (response.isSuccessful) {
val weatherResponse = response.body()
if (weatherResponse != null) {
Result.Success(weatherResponse)
val body = response.body()
if (body != null) {
Result.Success(body)
} else {
Result.Error(Exception("Empty response body"))
}

View File

@ -3,8 +3,12 @@ package com.example.weatherdemo.ui
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.weatherdemo.R
@ -20,64 +24,67 @@ class ChatActivity : AppCompatActivity() {
private lateinit var btnSend: Button
private lateinit var recyclerView: RecyclerView
private lateinit var chatAdapter: ChatAdapter
private lateinit var username: String // username user aktif
private lateinit var username: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ✅ penting: kita handle insets sendiri biar semua HP aman
WindowCompat.setDecorFitsSystemWindows(window, false)
setContentView(R.layout.activity_chat)
// Toolbar + tombol back
val toolbar = findViewById<Toolbar>(R.id.toolbarChat)
setSupportActionBar(toolbar)
toolbar.setNavigationOnClickListener { finish() }
// ✅ Ambil username dari Intent
username = intent.getStringExtra("username") ?: "Guest"
findViewById<TextView>(R.id.btnBack).setOnClickListener { finish() }
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() { finish() }
})
val root = findViewById<androidx.constraintlayout.widget.ConstraintLayout>(R.id.chatRoot)
// ✅ INI INTI FIX: kalau keyboard muncul, kasih padding bawah sebesar tinggi keyboard
ViewCompat.setOnApplyWindowInsetsListener(root) { v, insets ->
val ime = insets.getInsets(WindowInsetsCompat.Type.ime())
val sysBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
// padding atas biar tidak nabrak status bar, padding bawah ikut keyboard
v.setPadding(
v.paddingLeft,
sysBars.top,
v.paddingRight,
ime.bottom
)
insets
}
etMessage = findViewById(R.id.etMessage)
btnSend = findViewById(R.id.btnSend)
recyclerView = findViewById(R.id.recyclerView)
val layoutManager = LinearLayoutManager(this).apply {
stackFromEnd = true
}
recyclerView.layoutManager = layoutManager
// 🔥 WAJIB kirim username ke ChatAdapter
recyclerView.layoutManager = LinearLayoutManager(this).apply { stackFromEnd = true }
chatAdapter = ChatAdapter(username)
recyclerView.adapter = chatAdapter
btnSend.setOnClickListener {
val messageText = etMessage.text.toString().trim()
if (messageText.isNotEmpty()) {
val time = SimpleDateFormat(
"HH:mm",
Locale.getDefault()
).format(Date())
FirebaseUtils.sendMessage(
username = username,
message = messageText,
time = time
)
val time = SimpleDateFormat("HH:mm", Locale.getDefault()).format(Date())
FirebaseUtils.sendMessage(username = username, message = messageText, time = time)
etMessage.setText("")
}
}
// biar insets langsung diterapkan
ViewCompat.requestApplyInsets(root)
}
override fun onStart() {
super.onStart()
FirebaseUtils.getMessages { messages ->
chatAdapter.submitList(messages)
if (messages.isNotEmpty()) {
recyclerView.post {
recyclerView.scrollToPosition(messages.size - 1)
}
recyclerView.post { recyclerView.scrollToPosition(messages.size - 1) }
}
}
}

View File

@ -2,38 +2,33 @@ package com.example.weatherdemo.ui
import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.weatherdemo.R
import com.google.android.material.button.MaterialButton
class LoginActivity : AppCompatActivity() {
private lateinit var etUsername: EditText
private lateinit var btnLogin: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
etUsername = findViewById(R.id.etUsername)
btnLogin = findViewById(R.id.btnLogin)
val etUsername = findViewById<EditText>(R.id.etUsername)
val btnLogin = findViewById<MaterialButton>(R.id.btnLogin)
btnLogin.setOnClickListener {
val username = etUsername.text.toString().trim()
if (username.isNotEmpty()) {
if (username.isEmpty()) {
Toast.makeText(this, "Masukkan username dulu", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
val intent = Intent(this, MainActivity::class.java)
// ✅ FIX: key KONSISTEN
intent.putExtra("username", username)
startActivity(intent)
finish()
} else {
Toast.makeText(this, "Please enter a username", Toast.LENGTH_SHORT).show()
}
}
}
}

View File

@ -6,23 +6,25 @@ import android.os.Bundle
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.weatherdemo.R
import com.example.weatherdemo.data.api.RetrofitInstance
import com.example.weatherdemo.data.models.WeatherResponse
import com.example.weatherdemo.data.models.WeatherForecastResponse
import com.example.weatherdemo.data.repository.WeatherRepository
import com.example.weatherdemo.ui.adapter.DailyForecastAdapter
import com.example.weatherdemo.ui.adapter.HourlyForecastAdapter
import com.example.weatherdemo.viewmodel.WeatherViewModel
import com.example.weatherdemo.viewmodel.WeatherViewModelFactory
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.google.android.material.floatingactionbutton.FloatingActionButton
class MainActivity : AppCompatActivity() {
@ -30,26 +32,43 @@ class MainActivity : AppCompatActivity() {
WeatherViewModelFactory(WeatherRepository(RetrofitInstance.apiService))
}
private lateinit var hourlyAdapter: HourlyForecastAdapter
private lateinit var dailyAdapter: DailyForecastAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// ✅ FIX DI SINI SAJA
val username = intent.getStringExtra("username") ?: "Guest"
findViewById<TextView>(R.id.tvWelcomeMessage).text = "Welcome, $username!"
val tvWelcomeMessage = findViewById<TextView>(R.id.tvWelcomeMessage)
tvWelcomeMessage.text = "Welcome, $username!"
// FAB chat → kirim username ke ChatActivity
findViewById<FloatingActionButton>(R.id.fabChat).setOnClickListener {
// ✅ CHAT GLOBAL → ImageButton (BUKAN FloatingActionButton)
findViewById<ImageButton>(R.id.fabChat).setOnClickListener {
val i = Intent(this, ChatActivity::class.java)
i.putExtra("username", username)
startActivity(i)
}
initForecastLists()
initViews()
setupObservers()
viewModel.fetchWeatherData("London")
// default city (AMAN)
viewModel.fetchForecast("Bekasi", days = 3)
}
private fun initForecastLists() {
hourlyAdapter = HourlyForecastAdapter()
findViewById<RecyclerView>(R.id.rvHourlyForecast).apply {
layoutManager = LinearLayoutManager(this@MainActivity, LinearLayoutManager.HORIZONTAL, false)
adapter = hourlyAdapter
}
dailyAdapter = DailyForecastAdapter()
findViewById<RecyclerView>(R.id.rvDailyForecast).apply {
layoutManager = LinearLayoutManager(this@MainActivity)
adapter = dailyAdapter
}
}
private fun initViews() {
@ -60,7 +79,7 @@ class MainActivity : AppCompatActivity() {
val location = etSearch.text.toString().trim()
if (location.isNotEmpty()) {
hideKeyboard()
viewModel.fetchWeatherData(location)
viewModel.fetchForecast(location, days = 3)
} else {
Toast.makeText(this, "Please enter a location", Toast.LENGTH_SHORT).show()
}
@ -68,78 +87,73 @@ class MainActivity : AppCompatActivity() {
}
private fun setupObservers() {
viewModel.weatherData.observe(this, Observer { weatherData ->
weatherData?.let { updateWeatherUI(it) }
})
viewModel.forecastData.observe(this) { forecast ->
forecast?.let { updateWeatherUI(it) }
}
viewModel.isLoading.observe(this, Observer { isLoading ->
viewModel.isLoading.observe(this) { isLoading ->
findViewById<ProgressBar>(R.id.progressBar).visibility =
if (isLoading) View.VISIBLE else View.GONE
})
viewModel.errorMessage.observe(this, Observer { errorMessage ->
val tvError = findViewById<TextView>(R.id.tvError)
if (errorMessage.isNotEmpty()) {
tvError.text = errorMessage
tvError.visibility = View.VISIBLE
findViewById<MaterialCardView>(R.id.weatherCard).visibility = View.GONE
Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show()
} else {
tvError.visibility = View.GONE
}
})
}
private fun updateWeatherUI(weatherResponse: WeatherResponse) {
viewModel.errorMessage.observe(this) { errorMessage ->
findViewById<TextView>(R.id.tvError).apply {
text = errorMessage
visibility = if (errorMessage.isNullOrBlank()) View.GONE else View.VISIBLE
}
}
}
private fun updateWeatherUI(weather: WeatherForecastResponse) {
val weatherCard = findViewById<MaterialCardView>(R.id.weatherCard)
val tvLocation = findViewById<TextView>(R.id.tvLocation)
val tvTemperature = findViewById<TextView>(R.id.tvTemperature)
val tvCondition = findViewById<TextView>(R.id.tvCondition)
val tvFeelsLike = findViewById<TextView>(R.id.tvFeelsLike)
val tvHumidity = findViewById<TextView>(R.id.tvHumidity)
val tvWind = findViewById<TextView>(R.id.tvWind)
val ivBg = findViewById<ImageView>(R.id.ivBg)
tvLocation.text = "${weatherResponse.location.name}, ${weatherResponse.location.country}"
tvTemperature.text = "${weatherResponse.current.temp_c}°C"
tvCondition.text = weatherResponse.current.condition.text
tvFeelsLike.text = "${weatherResponse.current.feelslike_c}°C"
tvHumidity.text = "${weatherResponse.current.humidity}%"
tvWind.text = "${weatherResponse.current.wind_kph} km/h"
val condition = weatherResponse.current.condition.text.lowercase()
val mainLayout = findViewById<LinearLayout>(R.id.mainLayout)
findViewById<TextView>(R.id.tvLocation).text =
"${weather.location.name}, ${weather.location.country}"
findViewById<TextView>(R.id.tvTemperature).text =
"${weather.current.temp_c}°C"
findViewById<TextView>(R.id.tvCondition).text =
weather.current.condition.text
findViewById<TextView>(R.id.tvFeelsLike).text =
"${weather.current.feelslike_c}°C"
findViewById<TextView>(R.id.tvHumidity).text =
"${weather.current.humidity}%"
findViewById<TextView>(R.id.tvWind).text =
"${weather.current.wind_kph} km/h"
// ✅ BACKGROUND FIX (no typo)
val condition = weather.current.condition.text.lowercase()
when {
condition.contains("clear") || condition.contains("sunny") -> {
weatherCard.setCardBackgroundColor(ContextCompat.getColor(this, R.color.sunny))
mainLayout.setBackgroundColor(ContextCompat.getColor(this, R.color.sunny_background))
}
condition.contains("rain") -> {
weatherCard.setCardBackgroundColor(ContextCompat.getColor(this, R.color.rainy))
mainLayout.setBackgroundColor(ContextCompat.getColor(this, R.color.rainy_background))
}
condition.contains("cloudy") -> {
weatherCard.setCardBackgroundColor(ContextCompat.getColor(this, R.color.cloudy))
mainLayout.setBackgroundColor(ContextCompat.getColor(this, R.color.cloudy_background))
}
condition.contains("snow") -> {
weatherCard.setCardBackgroundColor(ContextCompat.getColor(this, R.color.snowy))
mainLayout.setBackgroundColor(ContextCompat.getColor(this, R.color.snowy_background))
}
else -> {
weatherCard.setCardBackgroundColor(ContextCompat.getColor(this, R.color.default_weather))
mainLayout.setBackgroundColor(ContextCompat.getColor(this, R.color.default_weather_background))
}
condition.contains("sunny") || condition.contains("clear") ->
ivBg.setImageResource(R.drawable.sunny)
condition.contains("rain") || condition.contains("drizzle") || condition.contains("thunder") ->
ivBg.setImageResource(R.drawable.rainy)
condition.contains("cloud") || condition.contains("overcast") || condition.contains("mist") || condition.contains("fog") ->
ivBg.setImageResource(R.drawable.cloudy)
condition.contains("snow") || condition.contains("sleet") || condition.contains("blizzard") ->
ivBg.setImageResource(R.drawable.snowy)
else ->
ivBg.setImageResource(R.drawable.defaultt)
}
// forecast
val hourly = weather.forecast.forecastday.firstOrNull()?.hour.orEmpty().take(12)
hourlyAdapter.submitList(hourly)
dailyAdapter.submitList(weather.forecast.forecastday)
weatherCard.visibility = View.VISIBLE
}
private fun hideKeyboard() {
val view = this.currentFocus
view?.let {
currentFocus?.let {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(it.windowToken, 0)
it.clearFocus()
}
}
}

View File

@ -0,0 +1,43 @@
package com.example.weatherdemo.ui.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.weatherdemo.R
import com.example.weatherdemo.data.models.ForecastDay
class DailyForecastAdapter(
private var items: List<ForecastDay> = emptyList()
) : RecyclerView.Adapter<DailyForecastAdapter.DayVH>() {
fun submitList(newItems: List<ForecastDay>) {
items = newItems
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DayVH {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_day_forecast, parent, false)
return DayVH(view)
}
override fun onBindViewHolder(holder: DayVH, position: Int) {
holder.bind(items[position])
}
override fun getItemCount(): Int = items.size
class DayVH(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val tvDate: TextView = itemView.findViewById(R.id.tvDate)
private val tvRange: TextView = itemView.findViewById(R.id.tvTempRange)
private val tvCondition: TextView = itemView.findViewById(R.id.tvDayCondition)
fun bind(item: ForecastDay) {
tvDate.text = item.date
tvRange.text = "${item.day.mintemp_c}°C - ${item.day.maxtemp_c}°C"
tvCondition.text = item.day.condition.text
}
}
}

View File

@ -0,0 +1,45 @@
package com.example.weatherdemo.ui.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.weatherdemo.R
import com.example.weatherdemo.data.models.Hour
class HourlyForecastAdapter(
private var items: List<Hour> = emptyList()
) : RecyclerView.Adapter<HourlyForecastAdapter.HourVH>() {
fun submitList(newItems: List<Hour>) {
items = newItems
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HourVH {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_hour_forecast, parent, false)
return HourVH(view)
}
override fun onBindViewHolder(holder: HourVH, position: Int) {
holder.bind(items[position])
}
override fun getItemCount(): Int = items.size
class HourVH(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val tvHour: TextView = itemView.findViewById(R.id.tvHour)
private val tvTemp: TextView = itemView.findViewById(R.id.tvHourTemp)
private val tvCondition: TextView = itemView.findViewById(R.id.tvHourCondition)
fun bind(item: Hour) {
// item.time example: "2025-12-29 13:00"
val hourText = item.time.substringAfter(" ").ifBlank { item.time }
tvHour.text = hourText
tvTemp.text = "${item.temp_c}°C"
tvCondition.text = item.condition.text
}
}
}

View File

@ -4,10 +4,10 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.weatherdemo.data.models.WeatherResponse
import com.example.weatherdemo.data.models.WeatherForecastResponse
import com.example.weatherdemo.data.repository.WeatherRepository
import kotlinx.coroutines.launch
import com.example.weatherdemo.utils.Result
import kotlinx.coroutines.launch
/**
* ViewModel class that prepares and manages UI-related data
@ -16,9 +16,9 @@ import com.example.weatherdemo.utils.Result
*/
class WeatherViewModel(private val repository: WeatherRepository) : ViewModel() {
// LiveData for weather information - observed by UI
private val _weatherData = MutableLiveData<WeatherResponse>()
val weatherData: LiveData<WeatherResponse> = _weatherData
// LiveData for forecast response (current + hourly + daily)
private val _forecastData = MutableLiveData<WeatherForecastResponse>()
val forecastData: LiveData<WeatherForecastResponse> = _forecastData
// LiveData for loading state - to show/hide progress bar
private val _isLoading = MutableLiveData<Boolean>()
@ -29,17 +29,15 @@ class WeatherViewModel(private val repository: WeatherRepository) : ViewModel()
val errorMessage: LiveData<String> = _errorMessage
/**
* Fetches weather data for a given location
* Uses coroutines for background operations
* @param location The city name to search for
* Fetches forecast data for a given location
*/
fun fetchWeatherData(location: String) {
fun fetchForecast(location: String, days: Int = 3) {
_isLoading.value = true
viewModelScope.launch {
when (val result = repository.getWeatherData(location)) {
when (val result = repository.getWeatherForecast(location, days)) {
is Result.Success -> {
_weatherData.value = result.data
_forecastData.value = result.data
_errorMessage.value = ""
}
is Result.Error -> {

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -1,53 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/chatRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@drawable/background_gradient">
android:layout_height="match_parent">
<!-- TOOLBAR + TOMBOL BACK -->
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbarChat"
android:layout_width="match_parent"
<!-- TOP BAR -->
<RelativeLayout
android:id="@+id/topBar"
android:layout_width="0dp"
android:layout_height="56dp"
android:background="@color/button_color"
app:title="Global Chat"
app:titleTextColor="@android:color/white"
app:navigationIcon="@android:drawable/ic_media_previous" />
android:background="#2F55F4"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:gravity="center_vertical"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<!-- RecyclerView -->
<TextView
android:id="@+id/btnBack"
android:layout_width="48dp"
android:layout_height="48dp"
android:gravity="center"
android:text="←"
android:textSize="26sp"
android:textStyle="bold"
android:textColor="@android:color/white" />
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/btnBack"
android:layout_centerVertical="true"
android:layout_marginStart="8dp"
android:text="Chat Global"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@android:color/white" />
</RelativeLayout>
<!-- CHAT LIST -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="8dp"
android:scrollbars="vertical"
android:paddingBottom="8dp"
android:clipToPadding="false"
/>
app:layout_constraintTop_toBottomOf="@id/topBar"
app:layout_constraintBottom_toTopOf="@id/inputBar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<!-- INPUT BAR -->
<LinearLayout
android:id="@+id/inputBar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp"
android:background="#F2F2F2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<!-- Input -->
<EditText
android:id="@+id/etMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_height="44dp"
android:layout_weight="1"
android:textColor="@android:color/black"
android:textColorHint="#88000000"
android:hint="Type a message"
android:inputType="text"
android:padding="10dp"
android:layout_marginTop="8dp"
android:background="@android:color/white" />
android:background="@android:color/white"
android:padding="12dp" />
<!-- Send -->
<Button
android:id="@+id/btnSend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_height="44dp"
android:text="Send"
android:layout_marginTop="12dp"
android:layout_marginBottom="16dp"
android:textColor="@android:color/white"
android:background="@color/button_color" />
android:textAllCaps="false"
android:layout_marginStart="8dp"
android:backgroundTint="#2F55F4"
android:textColor="@android:color/white" />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,28 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
android:gravity="center"
android:background="@drawable/background_gradient">
android:background="@android:color/white">
<ImageView
android:id="@+id/ivLogo"
android:layout_width="320dp"
android:layout_height="320dp"
android:src="@drawable/ic_weatherhub"
android:scaleType="fitCenter"
android:adjustViewBounds="true"
android:contentDescription="WeatherHub Logo"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/tvAppName"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintVertical_chainStyle="packed"
android:layout_marginTop="10dp"
android:layout_marginBottom="6dp"/>
<TextView
android:id="@+id/tvAppName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="WeatherHub"
android:textStyle="bold"
android:textSize="22sp"
android:textColor="@android:color/black"
app:layout_constraintTop_toBottomOf="@id/ivLogo"
app:layout_constraintBottom_toTopOf="@id/cardUsername"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginBottom="44dp"/>
<!-- INPUT = ukuran sama dengan button -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/cardUsername"
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_marginStart="44dp"
android:layout_marginEnd="44dp"
app:cardCornerRadius="28dp"
app:cardElevation="10dp"
app:cardUseCompatPadding="false"
app:cardBackgroundColor="#EEF0FF"
app:layout_constraintTop_toBottomOf="@id/tvAppName"
app:layout_constraintBottom_toTopOf="@id/btnLogin"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<!-- Username Input Field -->
<EditText
android:id="@+id/etUsername"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter username"
android:textColor="@color/black"
android:textColorHint="@color/gray"
android:background="@android:color/white"
android:padding="12dp" />
android:layout_height="match_parent"
android:minHeight="56dp"
android:background="@android:color/transparent"
android:gravity="center_vertical"
android:paddingStart="22dp"
android:paddingEnd="22dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:hint=" "
android:inputType="textPersonName"
android:textSize="16sp"
android:textColor="@android:color/black"
android:textColorHint="#8A8A8A"
android:includeFontPadding="false"/>
</com.google.android.material.card.MaterialCardView>
<!-- Login Button -->
<Button
<!-- BUTTON = sama height & radius -->
<com.google.android.material.button.MaterialButton
android:id="@+id/btnLogin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_marginStart="44dp"
android:layout_marginEnd="44dp"
android:layout_marginTop="16dp"
android:text="Login"
android:layout_marginTop="20dp" />
</LinearLayout>
android:textAllCaps="false"
android:textSize="16sp"
android:textColor="@android:color/white"
app:cornerRadius="28dp"
app:elevation="10dp"
app:backgroundTint="#2F55F4"
app:layout_constraintTop_toBottomOf="@id/cardUsername"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginBottom="90dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -2,142 +2,189 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/ivBg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background_gradient">
android:scaleType="centerCrop"
android:src="@drawable/defaultt"
android:contentDescription="Background" />
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#14000000" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
android:fillViewport="true"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:focusable="true"
android:focusableInTouchMode="true">
<LinearLayout
android:id="@+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/solid_background_color">
android:orientation="vertical">
<!-- Header -->
<androidx.cardview.widget.CardView
<!-- Welcome -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
app:cardCornerRadius="16dp"
android:layout_marginBottom="14dp"
app:cardCornerRadius="18dp"
app:cardElevation="8dp"
app:cardBackgroundColor="@color/welcome_card_background">
app:cardUseCompatPadding="false"
app:strokeWidth="0dp"
app:cardBackgroundColor="#2F55F4">
<TextView
android:id="@+id/tvWelcomeMessage"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="Welcome!"
android:textColor="@color/white"
android:textSize="24sp"
android:textColor="@android:color/white"
android:textSize="22sp"
android:textStyle="bold" />
</androidx.cardview.widget.CardView>
</com.google.android.material.card.MaterialCardView>
<!-- Search -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
app:cardCornerRadius="16dp"
app:cardElevation="8dp"
app:cardBackgroundColor="@color/card_background">
android:layout_marginBottom="14dp"
app:cardCornerRadius="18dp"
app:cardElevation="10dp"
app:cardUseCompatPadding="false"
app:strokeWidth="1dp"
app:strokeColor="#22FFFFFF"
app:cardBackgroundColor="#55FFFFFF">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp">
android:padding="14dp"
android:gravity="center_vertical">
<EditText
android:id="@+id/etSearch"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_height="44dp"
android:layout_weight="1"
android:hint="Enter city name"
android:textColor="@color/white"
android:textColorHint="@color/hint_color"
android:background="@android:color/transparent" />
android:textColor="@android:color/white"
android:textColorHint="#CCFFFFFF"
android:background="@android:color/transparent"
android:gravity="center_vertical"
android:paddingStart="12dp"
android:paddingEnd="12dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_height="44dp"
android:text="Search"
android:textColor="@color/white"
android:textAllCaps="false"
android:textColor="@android:color/white"
app:cornerRadius="0dp"
app:icon="@drawable/ic_search"
android:backgroundTint="@color/button_color" />
app:iconPadding="8dp"
app:backgroundTint="#2F55F4" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Progress -->
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone" />
android:visibility="gone"
android:layout_marginBottom="10dp" />
<!-- Error -->
<TextView
android:id="@+id/tvError"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/error_color"
android:textColor="#FFFF4444"
android:gravity="center"
android:visibility="gone"
android:layout_marginBottom="16dp" />
android:layout_marginBottom="10dp" />
<!-- Weather Data Card (ID WAJIB sama seperti di MainActivity.kt) -->
<!-- WEATHER OUTER -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/weatherCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:visibility="gone"
app:cardCornerRadius="24dp"
app:cardElevation="12dp"
app:cardBackgroundColor="@color/weather_card_background">
app:cardCornerRadius="22dp"
app:cardElevation="0dp"
app:cardUseCompatPadding="false"
app:strokeWidth="0dp"
app:cardBackgroundColor="@android:color/transparent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- BOX 1 -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="18dp"
app:cardElevation="10dp"
app:cardUseCompatPadding="false"
app:strokeWidth="1dp"
app:strokeColor="#22FFFFFF"
app:cardBackgroundColor="#26FFFFFF">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp">
android:padding="16dp">
<TextView
android:id="@+id/tvLocation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Location"
android:textSize="24sp"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="@color/white"
android:textColor="@android:color/white"
android:gravity="center"
android:layout_marginBottom="8dp" />
android:layout_marginBottom="6dp" />
<TextView
android:id="@+id/tvTemperature"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="--°C"
android:textSize="48sp"
android:textSize="44sp"
android:textStyle="bold"
android:textColor="@color/white"
android:textColor="@android:color/white"
android:gravity="center"
android:layout_marginBottom="16dp" />
android:layout_marginBottom="8dp" />
<TextView
android:id="@+id/tvCondition"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Condition"
android:textSize="18sp"
android:textColor="@color/white"
android:textSize="16sp"
android:textColor="@android:color/white"
android:gravity="center"
android:layout_marginBottom="24dp" />
android:layout_marginBottom="14dp" />
<GridLayout
android:layout_width="match_parent"
@ -148,66 +195,149 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Feels Like:"
android:textColor="@color/label_color"
android:textSize="14sp" />
android:textColor="#E6FFFFFF"
android:textSize="13sp" />
<TextView
android:id="@+id/tvFeelsLike"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--°C"
android:textColor="@color/white"
android:textSize="14sp"
android:textColor="@android:color/white"
android:textSize="13sp"
android:layout_gravity="end" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Humidity:"
android:textColor="@color/label_color"
android:textSize="14sp" />
android:textColor="#E6FFFFFF"
android:textSize="13sp" />
<TextView
android:id="@+id/tvHumidity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="--%"
android:textColor="@color/white"
android:textSize="14sp"
android:textColor="@android:color/white"
android:textSize="13sp"
android:layout_gravity="end" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Wind:"
android:textColor="@color/label_color"
android:textSize="14sp" />
android:textColor="#E6FFFFFF"
android:textSize="13sp" />
<TextView
android:id="@+id/tvWind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="-- km/h"
android:textColor="@color/white"
android:textSize="14sp"
android:textColor="@android:color/white"
android:textSize="13sp"
android:layout_gravity="end" />
</GridLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<View
android:layout_width="match_parent"
android:layout_height="20dp" />
<!-- BOX 2 -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="18dp"
app:cardElevation="2dp"
app:cardUseCompatPadding="false"
app:strokeWidth="1dp"
app:strokeColor="#22FFFFFF"
app:cardBackgroundColor="#26FFFFFF">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Prediksi per Jam (12 Jam ke Depan)"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textSize="15sp"
android:layout_marginTop="4dp"
android:layout_marginBottom="12dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvHourlyForecast"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never"
android:clipToPadding="false" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<View
android:layout_width="match_parent"
android:layout_height="20dp" />
<!-- BOX 3 -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="18dp"
app:cardElevation="2dp"
app:cardUseCompatPadding="false"
app:strokeWidth="1dp"
app:strokeColor="#22FFFFFF"
app:cardBackgroundColor="#26FFFFFF">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Prediksi per Hari (3 Hari)"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textSize="15sp"
android:layout_marginTop="4dp"
android:layout_marginBottom="12dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvDailyForecast"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
</ScrollView>
<!-- FAB CHAT GLOBAL -->
<com.google.android.material.floatingactionbutton.FloatingActionButton
<!-- Chat Global: pakai gambar dari drawable -->
<ImageButton
android:id="@+id/fabChat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="66dp"
android:layout_height="66dp"
android:layout_gravity="bottom|end"
android:layout_margin="20dp"
android:contentDescription="Chat Global"
app:tint="@android:color/white"
app:backgroundTint="@color/button_color" />
android:layout_margin="18dp"
android:background="@android:color/transparent"
android:src="@drawable/logo_chat"
android:scaleType="fitCenter"
android:contentDescription="Chat Global" />
</FrameLayout>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:orientation="vertical"
android:padding="10dp"
android:background="@android:color/transparent">
<TextView
android:id="@+id/tvDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="2025-12-29"
android:textStyle="bold"
android:textColor="@android:color/white"
android:textSize="13sp" />
<TextView
android:id="@+id/tvTempRange"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="18.1°C - 26.9°C"
android:textColor="@android:color/white"
android:textSize="15sp"
android:textStyle="bold"
android:layout_marginTop="4dp" />
<TextView
android:id="@+id/tvDayCondition"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sunny"
android:textColor="#E6FFFFFF"
android:textSize="11sp"
android:layout_marginTop="2dp" />
</LinearLayout>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="110dp"
android:layout_height="wrap_content"
android:layout_marginEnd="14dp"
android:orientation="vertical"
android:padding="6dp"
android:background="@android:color/transparent">
<TextView
android:id="@+id/tvHour"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="00:00"
android:textStyle="bold"
android:textColor="@android:color/white"
android:textSize="13sp"
android:gravity="center" />
<TextView
android:id="@+id/tvHourTemp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="19.8°C"
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold"
android:gravity="center"
android:layout_marginTop="4dp" />
<TextView
android:id="@+id/tvHourCondition"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Clear"
android:textColor="#E6FFFFFF"
android:textSize="11sp"
android:gravity="center"
android:layout_marginTop="2dp" />
</LinearLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<background android:drawable="@mipmap/ic_weatherhub"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<background android:drawable="@mipmap/ic_weatherhub"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -6,4 +6,7 @@
</style>
<style name="Theme.WeatherDemo" parent="Base.Theme.WeatherDemo" />
<style name="Theme.WeatherDemo.NoActionBar" parent="Theme.MaterialComponents.DayNight.NoActionBar">
</style>
</resources>