mirror of
https://github.com/hmalik144/Weather-apps.git
synced 2026-03-17 23:16:01 +00:00
- mid commit
This commit is contained in:
@@ -111,6 +111,7 @@ android {
|
|||||||
lint {
|
lint {
|
||||||
abortOnError false
|
abortOnError false
|
||||||
}
|
}
|
||||||
|
testBuildType "debug"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import org.junit.Before
|
|||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import tools.fastlane.screengrab.Screengrab
|
import tools.fastlane.screengrab.Screengrab
|
||||||
import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy
|
import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy
|
||||||
|
import tools.fastlane.screengrab.locale.LocaleTestRule
|
||||||
|
|
||||||
@Suppress("EmptyMethod")
|
@Suppress("EmptyMethod")
|
||||||
open class BaseTest<A : Activity>(
|
open class BaseTest<A : Activity>(
|
||||||
@@ -47,9 +48,15 @@ open class BaseTest<A : Activity>(
|
|||||||
@get:Rule
|
@get:Rule
|
||||||
var permissionRule = GrantPermissionRule.grant(Manifest.permission.ACCESS_COARSE_LOCATION)
|
var permissionRule = GrantPermissionRule.grant(Manifest.permission.ACCESS_COARSE_LOCATION)
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
var writePermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||||
|
|
||||||
@get:Rule
|
@get:Rule
|
||||||
var snapshotRule: SnapshotRule = SnapshotRule()
|
var snapshotRule: SnapshotRule = SnapshotRule()
|
||||||
|
|
||||||
|
@Rule @JvmField
|
||||||
|
val localeTestRule = LocaleTestRule()
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
Screengrab.setDefaultScreenshotStrategy(UiAutomatorScreenshotStrategy())
|
Screengrab.setDefaultScreenshotStrategy(UiAutomatorScreenshotStrategy())
|
||||||
|
|||||||
@@ -129,6 +129,16 @@ open class BaseTestRobot {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <VH : ViewHolder> clickSubViewInRecycler(
|
||||||
|
recyclerId: Int,
|
||||||
|
position: Int,
|
||||||
|
) {
|
||||||
|
scrollToRecyclerItemByPosition<VH>(recyclerId, position)
|
||||||
|
?.perform(
|
||||||
|
RecyclerViewActions.actionOnItemAtPosition<VH>(position, click())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun checkErrorOnTextEntry(resId: Int, errorMessage: String): ViewInteraction =
|
fun checkErrorOnTextEntry(resId: Int, errorMessage: String): ViewInteraction =
|
||||||
onView(withId(resId)).check(matches(checkErrorMessage(errorMessage)))
|
onView(withId(resId)).check(matches(checkErrorMessage(errorMessage)))
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.appttude.h_mal.monoWeather.robot
|
||||||
|
|
||||||
|
import com.appttude.h_mal.atlas_weather.BaseTestRobot
|
||||||
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
import com.appttude.h_mal.monoWeather.ui.home.adapter.forecastDaily.ViewHolderForecastDaily
|
||||||
|
import com.appttude.h_mal.monoWeather.ui.home.adapter.further.ViewHolderFurtherDetails
|
||||||
|
|
||||||
|
fun furtherInfoScreen(func: FurtherInfoScreen.() -> Unit) = FurtherInfoScreen().apply { func() }
|
||||||
|
class FurtherInfoScreen : BaseTestRobot() {
|
||||||
|
fun verifyMaxTemperature(temperature: Int) =
|
||||||
|
matchText(R.id.maxtemp, StringBuilder().append(temperature).append("°").toString())
|
||||||
|
fun verifyAverageTemperature(temperature: Int) =
|
||||||
|
matchText(R.id.averagetemp, StringBuilder().append(temperature).append("°").toString())
|
||||||
|
fun verifyMinTemperature(temperature: Int) =
|
||||||
|
matchText(R.id.minimumtemp, StringBuilder().append(temperature).append("°").toString())
|
||||||
|
|
||||||
|
fun verifyWindSpeed(speedText: String) =
|
||||||
|
matchText(R.id.windtext, speedText)
|
||||||
|
|
||||||
|
fun verifyHumidity(humidity: Int) =
|
||||||
|
matchText(R.id.humiditytext, humidity.toString())
|
||||||
|
fun verifyPrecipitation(precipitation: Int) =
|
||||||
|
matchText(R.id.preciptext, precipitation.toString())
|
||||||
|
|
||||||
|
fun verifyCloudCoverage(coverage: Int) =
|
||||||
|
matchText(R.id.cloudtext, coverage.toString())
|
||||||
|
|
||||||
|
fun verifyUvIndex(uv: Int) =
|
||||||
|
matchText(R.id.uvtext, uv.toString())
|
||||||
|
fun verifySunrise(sunrise: String) =
|
||||||
|
matchText(R.id.sunrisetext, sunrise)
|
||||||
|
fun verifySunset(sunset: String) =
|
||||||
|
matchText(R.id.sunsettext, sunset)
|
||||||
|
|
||||||
|
fun refresh() = pullToRefresh(R.id.swipe_refresh)
|
||||||
|
fun isDisplayed() = matchViewWaitFor(R.id.maxtemp)
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import androidx.test.espresso.matcher.ViewMatchers.withId
|
|||||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
import com.appttude.h_mal.atlas_weather.BaseTestRobot
|
import com.appttude.h_mal.atlas_weather.BaseTestRobot
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
import com.appttude.h_mal.atlas_weather.helpers.EspressoHelper.waitForView
|
||||||
import com.appttude.h_mal.atlas_weather.model.types.UnitType
|
import com.appttude.h_mal.atlas_weather.model.types.UnitType
|
||||||
|
|
||||||
|
|
||||||
@@ -45,4 +46,10 @@ class SettingsScreen : BaseTestRobot() {
|
|||||||
matchText(R.id.header_text, R.string.retrieve_warning)
|
matchText(R.id.header_text, R.string.retrieve_warning)
|
||||||
matchText(R.id.body_text, R.string.empty_retrieve_warning)
|
matchText(R.id.body_text, R.string.empty_retrieve_warning)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isDisplayed() {
|
||||||
|
waitForView(
|
||||||
|
withText("Metric")
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,8 @@ package com.appttude.h_mal.monoWeather.robot
|
|||||||
|
|
||||||
import com.appttude.h_mal.atlas_weather.BaseTestRobot
|
import com.appttude.h_mal.atlas_weather.BaseTestRobot
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
|
import com.appttude.h_mal.monoWeather.ui.home.adapter.forecastDaily.ViewHolderForecastDaily
|
||||||
|
import com.appttude.h_mal.monoWeather.ui.home.adapter.further.ViewHolderFurtherDetails
|
||||||
|
|
||||||
fun weatherScreen(func: WeatherScreen.() -> Unit) = WeatherScreen().apply { func() }
|
fun weatherScreen(func: WeatherScreen.() -> Unit) = WeatherScreen().apply { func() }
|
||||||
class WeatherScreen : BaseTestRobot() {
|
class WeatherScreen : BaseTestRobot() {
|
||||||
@@ -16,4 +18,8 @@ class WeatherScreen : BaseTestRobot() {
|
|||||||
matchText(R.id.header_text, R.string.retrieve_warning)
|
matchText(R.id.header_text, R.string.retrieve_warning)
|
||||||
matchText(R.id.body_text, R.string.empty_retrieve_warning)
|
matchText(R.id.body_text, R.string.empty_retrieve_warning)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun tapDayInformationByPosition(position: Int) {
|
||||||
|
clickSubViewInRecycler<ViewHolderForecastDaily>(R.id.forecast_listview, position)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -5,9 +5,11 @@ import com.appttude.h_mal.atlas_weather.BaseTest
|
|||||||
import com.appttude.h_mal.atlas_weather.model.types.UnitType
|
import com.appttude.h_mal.atlas_weather.model.types.UnitType
|
||||||
import com.appttude.h_mal.atlas_weather.ui.MainActivity
|
import com.appttude.h_mal.atlas_weather.ui.MainActivity
|
||||||
import com.appttude.h_mal.atlas_weather.utils.Stubs
|
import com.appttude.h_mal.atlas_weather.utils.Stubs
|
||||||
|
import com.appttude.h_mal.monoWeather.robot.furtherInfoScreen
|
||||||
import com.appttude.h_mal.monoWeather.robot.settingsScreen
|
import com.appttude.h_mal.monoWeather.robot.settingsScreen
|
||||||
import com.appttude.h_mal.monoWeather.robot.weatherScreen
|
import com.appttude.h_mal.monoWeather.robot.weatherScreen
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import tools.fastlane.screengrab.Screengrab
|
||||||
|
|
||||||
class HomePageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
|
class HomePageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
|
||||||
|
|
||||||
@@ -22,9 +24,27 @@ class HomePageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
|
|||||||
isDisplayed()
|
isDisplayed()
|
||||||
verifyCurrentTemperature(2)
|
verifyCurrentTemperature(2)
|
||||||
verifyCurrentLocation("Mock Location")
|
verifyCurrentLocation("Mock Location")
|
||||||
|
Screengrab.screenshot("HomeScreen")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun loadApp_validWeatherResponse_viewFurtherDetailsPage() {
|
||||||
|
weatherScreen {
|
||||||
|
isDisplayed()
|
||||||
|
verifyCurrentTemperature(2)
|
||||||
|
verifyCurrentLocation("Mock Location")
|
||||||
|
tapDayInformationByPosition(4)
|
||||||
|
}
|
||||||
|
furtherInfoScreen {
|
||||||
|
isDisplayed()
|
||||||
|
verifyMaxTemperature(12)
|
||||||
|
verifyAverageTemperature(9)
|
||||||
|
Screengrab.screenshot("FurtherInfoScreen")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun loadApp_changeToImperial_returnsValidPage() {
|
fun loadApp_changeToImperial_returnsValidPage() {
|
||||||
weatherScreen {
|
weatherScreen {
|
||||||
@@ -37,6 +57,7 @@ class HomePageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
|
|||||||
settingsScreen {
|
settingsScreen {
|
||||||
selectWeatherUnits(UnitType.IMPERIAL)
|
selectWeatherUnits(UnitType.IMPERIAL)
|
||||||
goBack()
|
goBack()
|
||||||
|
Screengrab.screenshot("SettingsScreen")
|
||||||
}
|
}
|
||||||
weatherScreen {
|
weatherScreen {
|
||||||
isDisplayed()
|
isDisplayed()
|
||||||
|
|||||||
18
app/src/debug/AndroidManifest.xml
Normal file
18
app/src/debug/AndroidManifest.xml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!-- Allows storing screenshots on external storage, where it can be accessed by ADB -->
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
|
<!-- Allows changing locales -->
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.CHANGE_CONFIGURATION"
|
||||||
|
tools:ignore="ProtectedPermissions" />
|
||||||
|
|
||||||
|
<!-- Allows changing SystemUI demo mode -->
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.DUMP"
|
||||||
|
tools:ignore="ProtectedPermissions" />
|
||||||
|
|
||||||
|
</manifest>
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="3"
|
android:layout_weight="3"
|
||||||
tools:text="85%" />
|
tools:text="33" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="3"
|
android:layout_weight="3"
|
||||||
tools:ignore="InOrMmUsage"
|
tools:ignore="InOrMmUsage"
|
||||||
tools:text="11mm" />
|
tools:text="30" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="3"
|
android:layout_weight="3"
|
||||||
tools:ignore="InOrMmUsage"
|
tools:ignore="InOrMmUsage"
|
||||||
tools:text="11mm" />
|
tools:text="27" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ fun <T> LiveData<T>.getOrAwaitValue(
|
|||||||
var data: T? = null
|
var data: T? = null
|
||||||
val latch = CountDownLatch(1)
|
val latch = CountDownLatch(1)
|
||||||
val observer = object : Observer<T> {
|
val observer = object : Observer<T> {
|
||||||
override fun onChanged(o: T?) {
|
override fun onChanged(o: T) {
|
||||||
data = o
|
data = o
|
||||||
latch.countDown()
|
latch.countDown()
|
||||||
this@getOrAwaitValue.removeObserver(this)
|
this@getOrAwaitValue.removeObserver(this)
|
||||||
|
|||||||
@@ -42,4 +42,25 @@ platform :android do
|
|||||||
json_key: "google-play-key.json",
|
json_key: "google-play-key.json",
|
||||||
package_name: "com.appttude.h_mal.atlas_weather")
|
package_name: "com.appttude.h_mal.atlas_weather")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "Capture screenshots"
|
||||||
|
lane :screenGrabMonoWeather do
|
||||||
|
build_android_app(
|
||||||
|
task: 'assemble',
|
||||||
|
build_type: 'Debug',
|
||||||
|
flavor: 'MonoWeather',
|
||||||
|
)
|
||||||
|
build_android_app(
|
||||||
|
task: 'assemble',
|
||||||
|
build_type: 'AndroidTest',
|
||||||
|
flavor: 'MonoWeather',
|
||||||
|
)
|
||||||
|
screengrab(
|
||||||
|
app_package_name: "com.appttude.h_mal.monoWeather",
|
||||||
|
locales: ["en-UK"],
|
||||||
|
app_apk_path: "app/build/outputs/apk/monoWeather/debug/app-monoWeather-debug.apk",
|
||||||
|
tests_apk_path: "app/build/outputs/apk/androidTest/monoWeather/debug/app-monoWeather-debug-androidTest.apk",
|
||||||
|
test_instrumentation_runner: "com.appttude.h_mal.atlas_weather.application.TestRunner",
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
64
readme.md
Normal file
64
readme.md
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
# Weather-apps
|
||||||
|
|
||||||
|
Weather-apps contains two weather apps - Atlas weather and Mono weather. They are both simple and user-friendly Android applications that provides current weather information and forecasts. With a sleek design and accurate data, to keeps you updated on the latest weather conditions in your area.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Current Weather**: Get real-time weather updates including temperature, humidity, wind speed, and atmospheric pressure.
|
||||||
|
- **Forecast**: View detailed weather forecasts for the next 7 days.
|
||||||
|
- **Location-Based Updates**: Automatically fetch weather data based on your current location.
|
||||||
|
- **Search Functionality**: Search for weather information in different cities around the world.
|
||||||
|
- **Notifications**: Receive weather alerts and notifications for significant weather changes.
|
||||||
|
- **Customizable Settings**: Choose between Celsius and Fahrenheit, and set your preferred update frequency.
|
||||||
|
- **Customizable Home screen widget**: Add a home screen widget to give you regular updates on forecast.
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
### Atlas Weather
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
### Mono Weather
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
1. Upon launching the app, you will be prompted to allow location access. Grant the necessary permissions.
|
||||||
|
2. The home screen will display the current weather information for your location.
|
||||||
|
3. Swipe left or tap on the forecast tab to view the 7-day weather forecast.
|
||||||
|
4. Use the search icon to look up weather information for other cities.
|
||||||
|
5. Access the settings menu to customize your preferences.
|
||||||
|
|
||||||
|
## Permissions
|
||||||
|
|
||||||
|
The app requires the following permissions:
|
||||||
|
|
||||||
|
- **Location**: To provide accurate weather information based on your current location.
|
||||||
|
- **Internet**: To fetch weather data from the server.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
Weather-apps
|
||||||
|
- uses the [OpenWeatherMap API](https://openweathermap.org/api) to retrieve weather data.
|
||||||
|
- uses the [TomTom Search API](https://developer.tomtom.com/search-api/documentation/product-information/introduction) to retrieve geolocation data.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! Please follow these steps:
|
||||||
|
|
||||||
|
1. Fork the repository.
|
||||||
|
2. Create a new branch: `git checkout -b feature/your-feature-name`
|
||||||
|
3. Make your changes and commit them: `git commit -m 'Add some feature'`
|
||||||
|
4. Push to the branch: `git push origin feature/your-feature-name`
|
||||||
|
5. Create a pull request.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||||
|
|
||||||
|
## Acknowledgements
|
||||||
|
|
||||||
|
- [OpenWeatherMap](https://openweathermap.org) for the weather data API.
|
||||||
|
- [TomTom Search API](https://developer.tomtom.com/search-api/documentation/product-information/introduction) for the geolocation API.
|
||||||
Reference in New Issue
Block a user