commit 68246777fd1ac1c1af65fc33293bd7241e41db72 Author: khaliqozil Date: Thu Nov 6 16:02:04 2025 +0800 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..e78ff38 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,18 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..639c779 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..c224ad5 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..b2c751a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/.kotlin/errors/errors-1761919802970.log b/.kotlin/errors/errors-1761919802970.log new file mode 100644 index 0000000..1219b50 --- /dev/null +++ b/.kotlin/errors/errors-1761919802970.log @@ -0,0 +1,4 @@ +kotlin version: 2.0.21 +error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output: + 1. Kotlin compile daemon is ready + diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..cf43e13 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,60 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) +} + +android { + namespace = "com.example.weatherdemo" + compileSdk = 36 + + defaultConfig { + applicationId = "com.example.weatherdemo" + minSdk = 24 + targetSdk = 36 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.material) + implementation(libs.androidx.activity) + implementation(libs.androidx.constraintlayout) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + + + implementation ("com.google.android.material:material:1.8.0") + + implementation ("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2") + implementation ("androidx.lifecycle:lifecycle-livedata-ktx:2.6.2") + + implementation ("com.squareup.retrofit2:retrofit:2.9.0") + implementation ("com.squareup.retrofit2:converter-gson:2.9.0") + implementation ("com.squareup.okhttp3:logging-interceptor:4.10.0") + + implementation ("androidx.activity:activity-ktx:1.7.2") +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/example/weatherdemo/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/example/weatherdemo/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..14aef3b --- /dev/null +++ b/app/src/androidTest/java/com/example/weatherdemo/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.weatherdemo + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.example.weatherdemo", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..1ca3593 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/weatherdemo/data/api/RetrofitInstance.kt b/app/src/main/java/com/example/weatherdemo/data/api/RetrofitInstance.kt new file mode 100644 index 0000000..afacad0 --- /dev/null +++ b/app/src/main/java/com/example/weatherdemo/data/api/RetrofitInstance.kt @@ -0,0 +1,44 @@ +package com.example.weatherdemo.data.api + +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import java.util.concurrent.TimeUnit + +/** + * Singleton object to create and provide Retrofit instance + * Ensures we have only one instance of Retrofit throughout the app + */ +object RetrofitInstance { + + // Base URL for Weather API + private const val BASE_URL = "http://api.weatherapi.com/v1/" + + // Create logging interceptor to see network requests in Logcat + private val loggingInterceptor = HttpLoggingInterceptor().apply { + level = HttpLoggingInterceptor.Level.BODY + } + + // Create OkHttpClient with logging and timeout configurations + private val okHttpClient = OkHttpClient.Builder() + .addInterceptor(loggingInterceptor) + .connectTimeout(30, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .build() + + // Lazy initialization of Retrofit instance + private val retrofit: Retrofit by lazy { + Retrofit.Builder() + .baseUrl(BASE_URL) + .client(okHttpClient) + .addConverterFactory(GsonConverterFactory.create()) + .build() + } + + // Lazy initialization of API service + val apiService: WeatherApiService by lazy { + retrofit.create(WeatherApiService::class.java) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/weatherdemo/data/api/WeatherApiService.kt b/app/src/main/java/com/example/weatherdemo/data/api/WeatherApiService.kt new file mode 100644 index 0000000..aa943e0 --- /dev/null +++ b/app/src/main/java/com/example/weatherdemo/data/api/WeatherApiService.kt @@ -0,0 +1,27 @@ +package com.example.weatherdemo.data.api + +import com.example.weatherdemo.data.models.WeatherResponse +import retrofit2.http.GET +import retrofit2.http.Query + +import retrofit2.Response + +/** + * Retrofit service interface for Weather API + * 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( + @Query("key") key: String, + @Query("q") query: String, + @Query("aqi") aqi: String = "yes" + ): Response +} \ No newline at end of file diff --git a/app/src/main/java/com/example/weatherdemo/data/models/WeatherResponse.kt b/app/src/main/java/com/example/weatherdemo/data/models/WeatherResponse.kt new file mode 100644 index 0000000..62886f2 --- /dev/null +++ b/app/src/main/java/com/example/weatherdemo/data/models/WeatherResponse.kt @@ -0,0 +1,38 @@ +package com.example.weatherdemo.data.models + +/** + * Main data class representing the entire weather response + * We're only extracting essential fields for this simple app + */ +data class WeatherResponse( + val location: Location, + val current: Current +) + +/** + * Location information data class + */ +data class Location( + val name: String, // City name + val country: String // Country name +) + +/** + * Current weather conditions data class + * We're selecting only the most relevant weather data + */ +data class Current( + val temp_c: Double, // Temperature in Celsius + val condition: Condition, // Weather condition (text and icon) + val humidity: Int, // Humidity percentage + val wind_kph: Double, // Wind speed in km/h + val feelslike_c: Double // "Feels like" temperature +) + +/** + * Weather condition details + */ +data class Condition( + val text: String, // Weather description (e.g., "Partly cloudy") + val icon: String // Weather icon URL +) diff --git a/app/src/main/java/com/example/weatherdemo/data/repository/WeatherRepository.kt b/app/src/main/java/com/example/weatherdemo/data/repository/WeatherRepository.kt new file mode 100644 index 0000000..0c61be2 --- /dev/null +++ b/app/src/main/java/com/example/weatherdemo/data/repository/WeatherRepository.kt @@ -0,0 +1,42 @@ +package com.example.weatherdemo.data.repository + +import com.example.weatherdemo.data.api.WeatherApiService +import com.example.weatherdemo.data.models.WeatherResponse +import com.example.weatherdemo.utils.Result +import retrofit2.Response + +/** + * Repository class that acts as a single source of truth for weather data + * Handles data operations and API calls + */ +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 + */ + suspend fun getWeatherData(location: String): Result { + return try { + // Make API call + val response: Response = apiService.getCurrentWeather( + key = "YOUR_API_KEY", // API key + query = location + ) + + // Check if response is successful + if (response.isSuccessful) { + val weatherResponse = response.body() + if (weatherResponse != null) { + Result.Success(weatherResponse) + } else { + Result.Error(Exception("Empty response body")) + } + } else { + Result.Error(Exception("API call failed: ${response.code()}")) + } + } catch (e: Exception) { + Result.Error(e) + } + } +} diff --git a/app/src/main/java/com/example/weatherdemo/ui/MainActivity.kt b/app/src/main/java/com/example/weatherdemo/ui/MainActivity.kt new file mode 100644 index 0000000..d4cdb0d --- /dev/null +++ b/app/src/main/java/com/example/weatherdemo/ui/MainActivity.kt @@ -0,0 +1,139 @@ +package com.example.weatherdemo.ui + +import android.content.Context +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.view.View +import android.view.inputmethod.InputMethodManager +import android.widget.EditText +import android.widget.ProgressBar +import android.widget.TextView +import android.widget.Toast +import androidx.activity.viewModels +import androidx.lifecycle.Observer +import com.example.weatherdemo.R +import com.example.weatherdemo.data.api.RetrofitInstance +import com.example.weatherdemo.data.models.WeatherResponse +import com.example.weatherdemo.data.repository.WeatherRepository +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 + +/** + * Main Activity class that handles UI and user interactions + * Observes ViewModel LiveData and updates UI accordingly + */ +class MainActivity : AppCompatActivity() { + + // Initialize ViewModel using viewModels delegate + private val viewModel: WeatherViewModel by viewModels { + // Create ViewModel with repository dependency + WeatherViewModelFactory( + WeatherRepository(RetrofitInstance.apiService) + ) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + // Initialize UI components + initViews() + + // Set up observers for LiveData + setupObservers() + + // Load default location weather + viewModel.fetchWeatherData("London") + } + + /** + * Initializes UI components and sets up click listeners + */ + private fun initViews() { + val btnSearch = findViewById(R.id.btnSearch) + val etSearch = findViewById(R.id.etSearch) + + btnSearch.setOnClickListener { + val location = etSearch.text.toString().trim() + if (location.isNotEmpty()) { + // Hide keyboard + hideKeyboard() + // Fetch weather data for entered location + viewModel.fetchWeatherData(location) + } else { + Toast.makeText(this, "Please enter a location", Toast.LENGTH_SHORT).show() + } + } + } + + /** + * Sets up observers for ViewModel LiveData + * Observes weather data, loading state, and error messages + */ + private fun setupObservers() { + // Observe weather data changes + viewModel.weatherData.observe(this, Observer { weatherData -> + weatherData?.let { + updateWeatherUI(it) + } + }) + + // Observe loading state + viewModel.isLoading.observe(this, Observer { isLoading -> + val progressBar = findViewById(R.id.progressBar) + progressBar.visibility = if (isLoading) View.VISIBLE else View.GONE + }) + + // Observe error messages + viewModel.errorMessage.observe(this, Observer { errorMessage -> + val tvError = findViewById(R.id.tvError) + if (errorMessage.isNotEmpty()) { + tvError.text = errorMessage + tvError.visibility = View.VISIBLE + // Hide weather card on error + findViewById(R.id.weatherCard).visibility = View.GONE + Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show() + } else { + tvError.visibility = View.GONE + } + }) + } + + /** + * Updates UI with weather data + * @param weatherResponse The weather data to display + */ + private fun updateWeatherUI(weatherResponse: WeatherResponse) { + val weatherCard = findViewById(R.id.weatherCard) + val tvLocation = findViewById(R.id.tvLocation) + val tvTemperature = findViewById(R.id.tvTemperature) + val tvCondition = findViewById(R.id.tvCondition) + val tvFeelsLike = findViewById(R.id.tvFeelsLike) + val tvHumidity = findViewById(R.id.tvHumidity) + val tvWind = findViewById(R.id.tvWind) + + // Update UI with weather data + 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" + + // Show weather card + weatherCard.visibility = View.VISIBLE + } + + /** + * Hides the soft keyboard + */ + private fun hideKeyboard() { + val view = this.currentFocus + view?.let { + val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(it.windowToken, 0) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/weatherdemo/utils/Result.kt b/app/src/main/java/com/example/weatherdemo/utils/Result.kt new file mode 100644 index 0000000..42c3237 --- /dev/null +++ b/app/src/main/java/com/example/weatherdemo/utils/Result.kt @@ -0,0 +1,10 @@ +package com.example.weatherdemo.utils + +/** + * Sealed class representing the result of API operations + * Can be either Success with data or Error with exception + */ +sealed class Result { + data class Success(val data: T) : Result() + data class Error(val exception: Exception) : Result() +} \ No newline at end of file diff --git a/app/src/main/java/com/example/weatherdemo/viewmodel/WeatherViewModel.kt b/app/src/main/java/com/example/weatherdemo/viewmodel/WeatherViewModel.kt new file mode 100644 index 0000000..81e5f11 --- /dev/null +++ b/app/src/main/java/com/example/weatherdemo/viewmodel/WeatherViewModel.kt @@ -0,0 +1,52 @@ +package com.example.weatherdemo.viewmodel + +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.repository.WeatherRepository +import kotlinx.coroutines.launch +import com.example.weatherdemo.utils.Result + +/** + * ViewModel class that prepares and manages UI-related data + * Survives configuration changes and acts as a communication center + * between Repository and UI + */ +class WeatherViewModel(private val repository: WeatherRepository) : ViewModel() { + + // LiveData for weather information - observed by UI + private val _weatherData = MutableLiveData() + val weatherData: LiveData = _weatherData + + // LiveData for loading state - to show/hide progress bar + private val _isLoading = MutableLiveData() + val isLoading: LiveData = _isLoading + + // LiveData for error messages - to show error states in UI + private val _errorMessage = MutableLiveData() + val errorMessage: LiveData = _errorMessage + + /** + * Fetches weather data for a given location + * Uses coroutines for background operations + * @param location The city name to search for + */ + fun fetchWeatherData(location: String) { + _isLoading.value = true + + viewModelScope.launch { + when (val result = repository.getWeatherData(location)) { + is Result.Success -> { + _weatherData.value = result.data + _errorMessage.value = "" + } + is Result.Error -> { + _errorMessage.value = result.exception.message ?: "Unknown error occurred" + } + } + _isLoading.value = false + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/weatherdemo/viewmodel/WeatherViewModelFactory.kt b/app/src/main/java/com/example/weatherdemo/viewmodel/WeatherViewModelFactory.kt new file mode 100644 index 0000000..89c256f --- /dev/null +++ b/app/src/main/java/com/example/weatherdemo/viewmodel/WeatherViewModelFactory.kt @@ -0,0 +1,26 @@ +package com.example.weatherdemo.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.example.weatherdemo.data.repository.WeatherRepository + +/** + * Factory class for creating WeatherViewModel instances + * Handles dependency injection for the ViewModel + */ +class WeatherViewModelFactory(private val repository: WeatherRepository) : ViewModelProvider.Factory { + + /** + * Creates a new instance of the WeatherViewModel class + * @param modelClass The class of the ViewModel to create + * @return Created ViewModel instance + * @throws IllegalArgumentException if the ViewModel class is unknown + */ + @Suppress("UNCHECKED_CAST") + override fun create(modelClass: Class): T { + if (modelClass.isAssignableFrom(WeatherViewModel::class.java)) { + return WeatherViewModel(repository) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/background_gradient.xml b/app/src/main/res/drawable/background_gradient.xml new file mode 100644 index 0000000..73a3e8f --- /dev/null +++ b/app/src/main/res/drawable/background_gradient.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_search.xml b/app/src/main/res/drawable/ic_search.xml new file mode 100644 index 0000000..d29c6ea --- /dev/null +++ b/app/src/main/res/drawable/ic_search.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..fbe1781 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml new file mode 100644 index 0000000..c26baa8 --- /dev/null +++ b/app/src/main/res/values-night/themes.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..156ddc1 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,18 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + + + #2196F3 + #FF5252 + #B3FFFFFF + #CCFFFFFF + #4DFFFFFF + #803496DB + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..00461f1 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Weather App + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..58bb8d2 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,9 @@ + + + + +