Flavours fixed

UI tests fixed
fastlane added
This commit is contained in:
2023-08-06 23:45:45 +01:00
parent 89be7be19f
commit 21103165fb
147 changed files with 810 additions and 1284 deletions

8
.gitignore vendored
View File

@@ -88,3 +88,11 @@ gen-external-apklibs
.idea/assetWizardSettings.xml
.idea/gradle.xml
.idea/jarRepositorie
# Gem/fastlane
/Gemfile.lock
/fastlane/report.xml
# Google play files
/google-play-key.json
/.idea/androidTestResultsUserPreferences.xml

View File

@@ -1,24 +1,13 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value>
<package name="java.util" alias="false" withSubpackages="false" />
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
<package name="io.ktor" alias="false" withSubpackages="true" />
</value>
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
@@ -127,5 +116,8 @@
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</codeStyleSettings>
</code_scheme>
</component>

6
.idea/kotlinc.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.6.0" />
</component>
</project>

3
Gemfile Normal file
View File

@@ -0,0 +1,3 @@
source "https://rubygems.org"
gem "fastlane"

View File

@@ -1,9 +1,9 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-android-extensions'
id 'kotlin-kapt'
id 'androidx.navigation.safeargs'
id 'kotlin-parcelize'
}
android {
lintOptions {
@@ -11,12 +11,12 @@ android {
}
compileSdkVersion 33
defaultConfig {
applicationId "com.appttude.h_mal"
applicationId "com.appttude.h_mal.atlas_weather"
minSdkVersion 26
targetSdkVersion 33
versionCode 5
versionName "3.0"
testInstrumentationRunner "com.appttude.h_mal.application.TestRunner"
testInstrumentationRunner "com.appttude.h_mal.atlas_weather.application.TestRunner"
vectorDrawables.useSupportLibrary = true
Properties properties = new Properties()

View File

@@ -0,0 +1,70 @@
package com.appttude.h_mal.atlas_weather
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.internal.inject.InstrumentationContext
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule
import com.appttude.h_mal.atlas_weather.application.TestAppClass
import com.appttude.h_mal.atlas_weather.helper.GenericsHelper.getGenericClassAt
import com.appttude.h_mal.atlas_weather.helpers.SnapshotRule
import com.appttude.h_mal.atlas_weather.utils.Stubs
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Rule
import tools.fastlane.screengrab.Screengrab
import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy
open class BaseTest<A : Activity>(
private val activity: Class<A>,
private val intentBundle: Bundle? = null,
) {
lateinit var scenario: ActivityScenario<A>
private lateinit var testApp: TestAppClass
@get:Rule
var permissionRule = GrantPermissionRule.grant(Manifest.permission.ACCESS_COARSE_LOCATION)
@get:Rule
var snapshotRule: SnapshotRule = SnapshotRule()
@Before
fun setUp() {
Screengrab.setDefaultScreenshotStrategy(UiAutomatorScreenshotStrategy())
val startIntent = Intent(InstrumentationRegistry.getInstrumentation().targetContext, activity)
if (intentBundle != null) {
startIntent.replaceExtras(intentBundle)
}
scenario = ActivityScenario.launch(startIntent)
scenario.onActivity {
runBlocking {
testApp = it.application as TestAppClass
beforeLaunch()
}
}
afterLaunch()
}
fun stubEndpoint(url: String, stub: Stubs) {
testApp.stubUrl(url, stub.id)
}
fun unstubEndpoint(url: String) {
testApp.removeUrlStub(url)
}
@After
fun tearDown() {
testFinished()
}
open fun beforeLaunch() {}
open fun afterLaunch() {}
open fun testFinished() {}
}

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather.utils
package com.appttude.h_mal.atlas_weather
import android.content.res.Resources
import android.view.View
@@ -16,14 +16,9 @@ import androidx.test.espresso.action.ViewActions.swipeDown
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.PickerActions
import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import androidx.test.espresso.matcher.ViewMatchers.withClassName
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import com.appttude.h_mal.atlas_weather.checkErrorMessage
import com.appttude.h_mal.atlas_weather.checkImage
import androidx.test.espresso.matcher.ViewMatchers.*
import com.appttude.h_mal.atlas_weather.helpers.checkErrorMessage
import com.appttude.h_mal.atlas_weather.helpers.checkImage
import com.appttude.h_mal.atlas_weather.helpers.EspressoHelper.waitForView
import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.CoreMatchers.anything
@@ -46,6 +41,8 @@ open class BaseTestRobot {
fun matchViewWaitFor(resId: Int): ViewInteraction = waitForView(withId(resId))
fun matchDisplayed(resId: Int): ViewInteraction = matchView(resId).check(matches(isDisplayed()))
fun matchText(viewInteraction: ViewInteraction, text: String): ViewInteraction = viewInteraction
.check(matches(withText(text)))
@@ -142,7 +139,7 @@ open class BaseTestRobot {
Resources.getSystem().getString(resId)
fun pullToRefresh(resId: Int){
onView(allOf(withId(resId), ViewMatchers.isDisplayed())).perform(swipeDown())
onView(allOf(withId(resId), isDisplayed())).perform(swipeDown())
}
fun selectDateInPicker(year: Int, month: Int, day: Int) {

View File

@@ -1,141 +0,0 @@
//package com.appttude.h_mal.atlas_weather
//
//import android.Manifest
//import android.R
//import android.app.Activity
//import android.content.Context
//import android.os.Build
//import android.view.View
//import android.view.WindowManager
//import androidx.annotation.StringRes
//import androidx.test.core.app.ActivityScenario
//import androidx.test.espresso.*
//import androidx.test.espresso.Espresso.onView
//import androidx.test.espresso.assertion.ViewAssertions.matches
//import androidx.test.espresso.matcher.ViewMatchers.*
//import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
//import androidx.test.rule.GrantPermissionRule
//import com.appttude.h_mal.atlas_weather.atlasWeather.ui.BaseActivity
////import h_mal.appttude.com.driver.base.BaseActivity
//import com.appttude.h_mal.atlas_weather.helpers.BaseViewAction
//import com.appttude.h_mal.atlas_weather.helpers.SnapshotRule
//import org.hamcrest.CoreMatchers
//import org.hamcrest.Description
//import org.hamcrest.Matcher
//import org.hamcrest.TypeSafeMatcher
//import org.hamcrest.core.AllOf
//import org.junit.After
//import org.junit.Before
//import org.junit.Rule
//import tools.fastlane.screengrab.Screengrab
//import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy
//import tools.fastlane.screengrab.locale.LocaleTestRule
//
//
//open class BaseUiTest<T : BaseActivity>(
// private val activity: Class<T>
//) {
//
// private lateinit var mActivityScenarioRule: ActivityScenario<T>
// private var mIdlingResource: IdlingResource? = null
//
// private lateinit var currentActivity: Activity
//
// @get:Rule
// var permissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE)
//
// @get:Rule
// var snapshotRule: SnapshotRule = SnapshotRule()
//
// @Rule
// @JvmField
// var localeTestRule = LocaleTestRule()
//
// @Before
// fun setup() {
// Screengrab.setDefaultScreenshotStrategy(UiAutomatorScreenshotStrategy())
// beforeLaunch()
// mActivityScenarioRule = ActivityScenario.launch(activity)
// mActivityScenarioRule.onActivity {
//// mIdlingResource = it.getIdlingResource()!!
//// IdlingRegistry.getInstance().register(mIdlingResource)
// afterLaunch(it)
// }
// }
//
// @After
// fun tearDown() {
// mIdlingResource?.let {
// IdlingRegistry.getInstance().unregister(it)
// }
// }
//
// fun getResourceString(@StringRes stringRes: Int): String {
// return getInstrumentation().targetContext.resources.getString(
// stringRes
// )
// }
//
// fun waitFor(delay: Long) {
// onView(isRoot()).perform(object : ViewAction {
// override fun getConstraints(): Matcher<View> = isRoot()
// override fun getDescription(): String = "wait for $delay milliseconds"
// override fun perform(uiController: UiController, v: View?) {
// uiController.loopMainThreadForAtLeast(delay)
// }
// })
// }
//
// open fun beforeLaunch() {}
// open fun afterLaunch(context: Context) {}
//
//
// @Suppress("DEPRECATION")
// fun checkToastMessage(message: String) {
// onView(withText(message)).inRoot(object : TypeSafeMatcher<Root>() {
// override fun describeTo(description: Description?) {
// description?.appendText("is toast")
// }
//
// override fun matchesSafely(root: Root): Boolean {
// root.run {
// if (windowLayoutParams.get().type == WindowManager.LayoutParams.TYPE_TOAST) {
// decorView.run {
// if (windowToken === applicationWindowToken) {
// // windowToken == appToken means this window isn't contained by any other windows.
// // if it was a window for an activity, it would have TYPE_BASE_APPLICATION.
// return true
// }
// }
// }
// }
// return false
// }
// }
// ).check(matches(isDisplayed()))
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
// waitFor(3500)
// }
// }
//
// fun checkSnackBarDisplayedByMessage(message: String) {
// onView(
// CoreMatchers.allOf(
// withId(com.google.android.material.R.id.snackbar_text),
// withText(message)
// )
// ).check(matches(isDisplayed()))
// }
//
// private fun getCurrentActivity(): Activity {
// onView(AllOf.allOf(withId(R.id.content), isDisplayed()))
// .perform(object : BaseViewAction() {
// override fun setPerform(uiController: UiController?, view: View?) {
// if (view?.context is Activity) {
// currentActivity = view.context as Activity
// }
// }
// })
// return currentActivity
// }
//}

View File

@@ -4,6 +4,7 @@ package com.appttude.h_mal.atlas_weather.data.location
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.appttude.h_mal.atlas_weather.data.location.LocationProviderImpl
import com.appttude.h_mal.atlas_weather.model.types.LocationType
import kotlinx.coroutines.runBlocking
import org.hamcrest.Matcher.*

View File

@@ -1,5 +1,6 @@
package com.appttude.h_mal.atlas_weather.data.location
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
import com.appttude.h_mal.atlas_weather.model.types.LocationType
class MockLocationProvider : LocationProvider {

View File

@@ -1,14 +0,0 @@
package com.appttude.h_mal.atlas_weather.helpers
import android.os.Environment
import java.io.File
/**
* File paths for images on device
*/
fun getImagePath(imageConst: String): String {
return File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
"/Camera/images/$imageConst"
).absolutePath
}

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather
package com.appttude.h_mal.atlas_weather.helpers
import android.graphics.drawable.BitmapDrawable
import android.view.View

View File

@@ -1,33 +0,0 @@
package com.appttude.h_mal.atlas_weather.helpers
import android.content.ClipData
import android.content.ClipData.Item
import android.net.Uri
import java.io.File
object DataHelper {
fun createClipItem(filePath: String) = Item(
Uri.fromFile(
File(filePath)
)
)
fun createClipData(item: Item, mimeType: String = "text/uri-list") =
ClipData(null, arrayOf(mimeType), item)
fun createClipData(filePath: String) = createClipData(createClipItem(filePath))
fun createClipData(filePaths: Array<String>): ClipData {
val clipData = createClipData(filePaths[0])
val remainingFiles = filePaths.copyOfRange(1, filePaths.size - 1)
clipData.addFilePaths(remainingFiles)
return clipData
}
fun createClipData(uri: Uri) = createClipData(Item(uri))
fun ClipData.addFilePaths(filePaths: Array<String>) {
filePaths.forEach { addItem(createClipItem(it)) }
}
}

View File

@@ -1,67 +0,0 @@
package com.appttude.h_mal.atlas_weather.testsuite
import android.Manifest
import android.app.Activity
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.RootMatchers.isDialog
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.ActivityTestRule
import androidx.test.rule.GrantPermissionRule
import com.appttude.h_mal.atlas_weather.application.TestAppClass
import com.appttude.h_mal.atlas_weather.helper.GenericsHelper.getGenericClassAt
import com.appttude.h_mal.atlas_weather.helpers.SnapshotRule
import com.appttude.h_mal.atlas_weather.utils.Stubs
import org.junit.After
import org.junit.Rule
import tools.fastlane.screengrab.Screengrab
import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy
open class BaseTest<A : Activity> {
lateinit var testApp: TestAppClass
@get:Rule
var permissionRule = GrantPermissionRule.grant(Manifest.permission.ACCESS_COARSE_LOCATION)
@get:Rule
var snapshotRule: SnapshotRule = SnapshotRule()
@Rule
@JvmField
var mActivityTestRule: ActivityTestRule<A> =
object : ActivityTestRule<A>(getGenericClassAt<A>(0).java) {
override fun beforeActivityLaunched() {
super.beforeActivityLaunched()
Screengrab.setDefaultScreenshotStrategy(UiAutomatorScreenshotStrategy())
testApp =
InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as TestAppClass
setupFeed()
}
override fun afterActivityLaunched() {
// Dismiss dialog
onView(withText("AGREE")).inRoot(isDialog()).check(matches(isDisplayed()))
.perform(ViewActions.click())
}
}
fun stubEndpoint(url: String, stub: Stubs) {
testApp.stubUrl(url, stub.id)
}
fun unstubEndpoint(url: String) {
testApp.removeUrlStub(url)
}
@After
fun tearDown() {
}
open fun setupFeed() {}
}

View File

@@ -1,81 +0,0 @@
package com.appttude.h_mal.atlas_weather.testsuite
import android.Manifest
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ActivityScenario.launch
import androidx.test.espresso.Espresso
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.assertion.ViewAssertions
import androidx.test.espresso.matcher.RootMatchers
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
import androidx.test.rule.GrantPermissionRule
import com.appttude.h_mal.atlas_weather.application.TestAppClass
import com.appttude.h_mal.atlas_weather.robot.homeScreen
import com.appttude.h_mal.atlas_weather.ui.MainActivity
import com.appttude.h_mal.atlas_weather.utils.Stubs
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4ClassRunner::class)
class HomePageUITestScenario : BaseMainScenario() {
override fun setupFeed() {
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Valid)
}
@Test
fun loadApp_validWeatherResponse_returnsValidPage() {
homeScreen {
verifyCurrentTemperature(2)
verifyCurrentLocation("Mock Location")
}
}
}
open class BaseMainScenario {
lateinit var scenario: ActivityScenario<MainActivity>
private lateinit var testApp: TestAppClass
@get:Rule
var permissionRule = GrantPermissionRule.grant(Manifest.permission.ACCESS_COARSE_LOCATION)
@Before
fun setUp() {
scenario = launch(MainActivity::class.java)
scenario.onActivity {
runBlocking {
testApp = it.application as TestAppClass
setupFeed()
}
}
// Dismiss dialog on start up
Espresso.onView(ViewMatchers.withText("AGREE"))
.inRoot(RootMatchers.isDialog())
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
.perform(ViewActions.click())
}
fun stubEndpoint(url: String, stub: Stubs) {
testApp.stubUrl(url, stub.id)
}
fun unstubEndpoint(url: String) {
testApp.removeUrlStub(url)
}
@After
fun tearDown() {
testFinished()
}
open fun setupFeed() {}
open fun testFinished() {}
}

View File

@@ -1,30 +0,0 @@
package com.appttude.h_mal.atlas_weather.ui.widget
import android.appwidget.AppWidgetManager
import android.content.Intent
import androidx.test.espresso.Espresso
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.rule.ActivityTestRule
import com.appttude.h_mal.atlas_weather.R
import org.junit.Rule
import org.junit.Test
class WidgetLocationPermissionActivityTest {
@Rule
@JvmField
var mActivityTestRule : ActivityTestRule<WidgetLocationPermissionActivity> =
ActivityTestRule(WidgetLocationPermissionActivity::class.java, false, false)
@Test
fun demo_test() {
val startIntent = Intent().apply {
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 112)
}
mActivityTestRule.launchActivity(startIntent)
Espresso.onView((ViewMatchers.withId(R.id.declaration_text))).check(matches(isDisplayed()));
}
}

View File

@@ -1,7 +1,7 @@
package com.appttude.h_mal.atlas_weather.robot
import com.appttude.h_mal.atlas_weather.BaseTestRobot
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.utils.BaseTestRobot
fun homeScreen(func: HomeScreenRobot.() -> Unit) = HomeScreenRobot().apply { func() }
class HomeScreenRobot : BaseTestRobot() {

View File

@@ -1,23 +1,15 @@
package com.appttude.h_mal.atlas_weather.tests
import androidx.test.rule.GrantPermissionRule
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.MainActivity
import com.appttude.h_mal.atlas_weather.BaseTest
import com.appttude.h_mal.atlas_weather.robot.homeScreen
import com.appttude.h_mal.atlas_weather.testsuite.BaseTest
import com.appttude.h_mal.atlas_weather.ui.MainActivity
import com.appttude.h_mal.atlas_weather.utils.Stubs
import org.junit.Rule
import org.junit.Test
class HomePageUITest : BaseTest<MainActivity>() {
class HomePageUITest : BaseTest<MainActivity>(activity = MainActivity::class.java) {
@Rule
@JvmField
var mGrantPermissionRule: GrantPermissionRule =
GrantPermissionRule.grant(
"android.permission.ACCESS_COARSE_LOCATION")
override fun setupFeed() {
override fun beforeLaunch() {
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Valid)
}

View File

@@ -0,0 +1,20 @@
package com.appttude.h_mal.monoWeather
import androidx.test.espresso.Espresso
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.assertion.ViewAssertions
import androidx.test.espresso.matcher.RootMatchers
import androidx.test.espresso.matcher.ViewMatchers
import com.appttude.h_mal.atlas_weather.BaseTest
import com.appttude.h_mal.atlas_weather.ui.MainActivity
open class MonoBaseTest: BaseTest<MainActivity>(MainActivity::class.java) {
override fun afterLaunch() {
// Dismiss dialog on start up
Espresso.onView(ViewMatchers.withText("AGREE"))
.inRoot(RootMatchers.isDialog())
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
.perform(ViewActions.click())
}
}

View File

@@ -1,7 +1,7 @@
package com.appttude.h_mal.atlas_weather.robot
package com.appttude.h_mal.monoWeather.robot
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.utils.BaseTestRobot
import com.appttude.h_mal.atlas_weather.BaseTestRobot
fun homeScreen(func: HomeScreenRobot.() -> Unit) = HomeScreenRobot().apply { func() }
class HomeScreenRobot : BaseTestRobot() {

View File

@@ -0,0 +1,11 @@
package com.appttude.h_mal.monoWeather.robot
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.BaseTestRobot
fun widgetPermissionScreen(func: WidgetPermissionScreenRobot.() -> Unit) =
WidgetPermissionScreenRobot().apply { func() }
class WidgetPermissionScreenRobot : BaseTestRobot() {
fun declarationDisplayed() = matchDisplayed(R.id.declaration_text)
}

View File

@@ -1,15 +1,14 @@
package com.appttude.h_mal.atlas_weather.tests
package com.appttude.h_mal.monoWeather.tests
import com.appttude.h_mal.atlas_weather.robot.homeScreen
import com.appttude.h_mal.atlas_weather.testsuite.BaseTest
import com.appttude.h_mal.atlas_weather.ui.MainActivity
import com.appttude.h_mal.monoWeather.robot.homeScreen
import com.appttude.h_mal.atlas_weather.utils.Stubs
import com.appttude.h_mal.monoWeather.MonoBaseTest
import org.junit.Test
class HomePageUITest : BaseTest<MainActivity>() {
class HomePageUITest : MonoBaseTest() {
override fun setupFeed() {
override fun beforeLaunch() {
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Valid)
}

View File

@@ -0,0 +1,26 @@
package com.appttude.h_mal.monoWeather.tests
import android.appwidget.AppWidgetManager
import android.content.Intent
import android.os.Bundle
import androidx.test.rule.ActivityTestRule
import com.appttude.h_mal.atlas_weather.BaseTest
import com.appttude.h_mal.monoWeather.robot.widgetPermissionScreen
import com.appttude.h_mal.monoWeather.ui.widget.WidgetLocationPermissionActivity
import org.junit.Test
class WidgetLocationPermissionActivityTest : BaseTest<WidgetLocationPermissionActivity>(
activity = WidgetLocationPermissionActivity::class.java,
intentBundle = Bundle().apply {
putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, 112)
}
) {
@Test
fun demo_test() {
widgetPermissionScreen {
declarationDisplayed()
}
}
}

View File

@@ -5,7 +5,7 @@
tools:node="merge">
<application
android:name="com.appttude.h_mal.application.AppClass"
android:name="com.appttude.h_mal.atlas_weather.application.AppClass"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
@@ -26,18 +26,12 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".atlasWeather.ui.settings.UnitSettingsActivity"
android:label="Settings"
android:exported="true"/>
<receiver
android:name=".atlasWeather.notification.NotificationReceiver"
android:name=".notification.NotificationReceiver"
android:parentActivityName=".MainActivity"
android:exported="true"/>
<receiver android:name=".atlasWeather.widget.NewAppWidget"
<receiver android:name=".widget.NewAppWidget"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@@ -49,11 +43,6 @@
android:name="android.appwidget.provider"
android:resource="@xml/new_app_widget_info" />
</receiver>
<service
android:name=".atlasWeather.widget.WidgetRemoteViewsService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
</application>
</manifest>

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.notification
package com.appttude.h_mal.atlas_weather.notification
import android.graphics.Bitmap

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.notification
package com.appttude.h_mal.atlas_weather.notification
import android.Manifest
import android.app.Notification
@@ -12,13 +12,10 @@ import android.content.pm.PackageManager
import android.os.Build
import androidx.core.app.ActivityCompat
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.MainActivity
import com.appttude.h_mal.atlas_weather.ui.MainActivity
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper
import com.appttude.h_mal.atlas_weather.model.weather.FullWeather
import com.appttude.h_mal.atlas_weather.utils.displayToast
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.kodein.di.KodeinAware
import org.kodein.di.LateInitKodein
import org.kodein.di.generic.instance

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.ui
package com.appttude.h_mal.atlas_weather.ui
import androidx.appcompat.app.AppCompatActivity

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.ui
package com.appttude.h_mal.atlas_weather.ui
import android.annotation.SuppressLint
import android.content.pm.PackageManager

View File

@@ -0,0 +1,5 @@
package com.appttude.h_mal.atlas_weather.ui
import com.appttude.h_mal.atlas_weather.R
val tabs = setOf(R.id.nav_home, R.id.nav_world)

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.ui
package com.appttude.h_mal.atlas_weather.ui
import android.os.Bundle
import android.view.LayoutInflater
@@ -8,7 +8,7 @@ import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.model.forecast.WeatherDisplay
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.home.adapter.WeatherRecyclerAdapter
import com.appttude.h_mal.atlas_weather.ui.home.adapter.WeatherRecyclerAdapter
import com.appttude.h_mal.atlas_weather.utils.navigateTo
import kotlinx.android.synthetic.main.fragment_home.*

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.details
package com.appttude.h_mal.atlas_weather.ui.details
import android.os.Bundle
import android.view.LayoutInflater

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.home
package com.appttude.h_mal.atlas_weather.ui.home
import android.Manifest
import android.annotation.SuppressLint
@@ -13,8 +13,8 @@ import androidx.lifecycle.observe
import androidx.recyclerview.widget.LinearLayoutManager
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.application.LOCATION_PERMISSION_REQUEST
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.BaseFragment
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.home.adapter.WeatherRecyclerAdapter
import com.appttude.h_mal.atlas_weather.ui.BaseFragment
import com.appttude.h_mal.atlas_weather.ui.home.adapter.WeatherRecyclerAdapter
import com.appttude.h_mal.atlas_weather.utils.displayToast
import com.appttude.h_mal.atlas_weather.utils.navigateTo
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.home.adapter
package com.appttude.h_mal.atlas_weather.ui.home.adapter
import android.view.View
import androidx.recyclerview.widget.RecyclerView

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.home.adapter
package com.appttude.h_mal.atlas_weather.ui.home.adapter
import android.view.View
import android.widget.ImageView

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.home.adapter
package com.appttude.h_mal.atlas_weather.ui.home.adapter
import android.view.View
import android.widget.ImageView

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.home.adapter
package com.appttude.h_mal.atlas_weather.ui.home.adapter
import android.view.View
import android.widget.TextView

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.home.adapter
package com.appttude.h_mal.atlas_weather.ui.home.adapter
import android.annotation.SuppressLint
import android.view.View

View File

@@ -0,0 +1,61 @@
package com.appttude.h_mal.atlas_weather.ui.settings
import android.app.AlarmManager
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.notification.NotificationReceiver
import com.appttude.h_mal.atlas_weather.widget.NewAppWidget
import java.util.Calendar
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.prefs, rootKey)
//listener on changed sort order preference:
val prefs = PreferenceManager.getDefaultSharedPreferences(requireContext())
prefs.registerOnSharedPreferenceChangeListener { _, key ->
if (key == "temp_units") {
val intent = Intent(requireContext(), NewAppWidget::class.java)
intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
val ids = AppWidgetManager.getInstance(requireContext())
.getAppWidgetIds(ComponentName(requireContext(), NewAppWidget::class.java))
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
requireContext().sendBroadcast(intent)
}
if (key == "notif_boolean") {
setupNotificationBroadcaster(requireContext())
}
if (key == "widget_black_background"){
val intent = Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE)
val widgetManager = AppWidgetManager.getInstance(requireContext())
val ids =
widgetManager.getAppWidgetIds(ComponentName(requireContext(), NewAppWidget::class.java))
AppWidgetManager.getInstance(requireContext())
.notifyAppWidgetViewDataChanged(ids, R.id.whole_widget_view)
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
requireContext().sendBroadcast(intent)
}
}
}
fun setupNotificationBroadcaster(context: Context) {
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val notificationIntent = Intent(context, NotificationReceiver::class.java)
val broadcast = PendingIntent.getBroadcast(context, 100, notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT)
val cal: Calendar = Calendar.getInstance()
cal.set(Calendar.HOUR_OF_DAY, 6)
cal.set(Calendar.MINUTE, 8)
cal.set(Calendar.SECOND, 5)
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.timeInMillis, AlarmManager.INTERVAL_DAY, broadcast)
}
}

View File

@@ -1,88 +0,0 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.settings
import android.app.AlarmManager
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.os.Bundle
import android.preference.PreferenceActivity
import android.preference.PreferenceFragment
import androidx.preference.PreferenceManager
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.atlasWeather.notification.NotificationReceiver
import com.appttude.h_mal.atlas_weather.atlasWeather.widget.NewAppWidget
import java.util.*
class UnitSettingsActivity : PreferenceActivity() {
private var prefListener: OnSharedPreferenceChangeListener? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
PreferenceManager.setDefaultValues(this, R.xml.prefs, false)
fragmentManager.beginTransaction().replace(android.R.id.content, MyPreferenceFragment()).commit()
//listener on changed sort order preference:
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
prefListener = OnSharedPreferenceChangeListener { _, key ->
if (key == "temp_units") {
val intent = Intent(baseContext, NewAppWidget::class.java)
intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
val ids = AppWidgetManager.getInstance(application).getAppWidgetIds(ComponentName(application, NewAppWidget::class.java))
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
sendBroadcast(intent)
}
if (key == "notif_boolean") {
setupNotificationBroadcaster(baseContext)
}
if (key == "widget_black_background"){
val intent = Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE)
val widgetManager = AppWidgetManager.getInstance(this)
val ids = widgetManager.getAppWidgetIds(ComponentName(this, NewAppWidget::class.java))
AppWidgetManager.getInstance(this).notifyAppWidgetViewDataChanged(ids, R.id.whole_widget_view)
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
sendBroadcast(intent)
}
}
prefs.registerOnSharedPreferenceChangeListener(prefListener)
}
fun setupNotificationBroadcaster(context: Context) {
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val notificationIntent = Intent(context, NotificationReceiver::class.java)
val broadcast = PendingIntent.getBroadcast(context, 100, notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT)
val cal: Calendar = Calendar.getInstance()
cal.set(Calendar.HOUR_OF_DAY, 6)
cal.set(Calendar.MINUTE, 8)
cal.set(Calendar.SECOND, 5)
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.timeInMillis, AlarmManager.INTERVAL_DAY, broadcast)
}
override fun onBackPressed() {
super.onBackPressed()
}
// @Override
// public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
// Log.i(TAG, "onSharedPreferenceChanged: " + s);
// if (s == "temp_units"){
// Intent intent = new Intent(getBaseContext(), NewAppWidget.class);
// intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
//
// int[] ids = AppWidgetManager.getInstance(getApplication()).getAppWidgetIds(new ComponentName(getApplication(), NewAppWidget.class));
// intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
// sendBroadcast(intent);
// }
// }
class MyPreferenceFragment : PreferenceFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
addPreferencesFromResource(R.xml.prefs)
}
}
}

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.world
package com.appttude.h_mal.atlas_weather.ui.world
import android.os.Bundle
import android.view.LayoutInflater
@@ -7,7 +7,7 @@ import android.view.ViewGroup
import androidx.fragment.app.viewModels
import androidx.lifecycle.observe
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.BaseFragment
import com.appttude.h_mal.atlas_weather.ui.BaseFragment
import com.appttude.h_mal.atlas_weather.utils.displayToast
import com.appttude.h_mal.atlas_weather.utils.goBack
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.world
package com.appttude.h_mal.atlas_weather.ui.world
import android.os.Bundle
import android.view.LayoutInflater
@@ -9,9 +9,9 @@ import androidx.fragment.app.viewModels
import androidx.lifecycle.observe
import androidx.recyclerview.widget.LinearLayoutManager
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.world.WorldRecyclerAdapter
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.BaseFragment
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.world.WorldFragmentDirections
import com.appttude.h_mal.atlas_weather.ui.world.WorldRecyclerAdapter
import com.appttude.h_mal.atlas_weather.ui.BaseFragment
import com.appttude.h_mal.atlas_weather.ui.world.WorldFragmentDirections
import com.appttude.h_mal.atlas_weather.utils.navigateTo
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.ui.world
package com.appttude.h_mal.atlas_weather.ui.world
import android.view.View
import android.view.ViewGroup

View File

@@ -1,38 +0,0 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.widget
import android.app.Activity
import android.app.PendingIntent
import android.app.TaskStackBuilder
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.content.Intent
import android.widget.RemoteViews
import androidx.annotation.LayoutRes
abstract class BaseWidgetClass : AppWidgetProvider(){
fun createRemoteView(context: Context, @LayoutRes id: Int): RemoteViews {
return RemoteViews(context.packageName, id)
}
fun AppWidgetProvider.createUpdatePendingIntent(context: Context, appWidgetId: Int): PendingIntent? {
val seconds = (System.currentTimeMillis() / 1000L).toInt()
val intentUpdate = Intent(context, this::class.java)
intentUpdate.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
val idArray = intArrayOf(appWidgetId)
intentUpdate.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, idArray)
return PendingIntent.getBroadcast(
context, seconds, intentUpdate,
PendingIntent.FLAG_UPDATE_CURRENT)
}
fun <T: Activity> createClickingPendingIntent(context: Context, activityClass: Class<T>): PendingIntent {
val clickIntentTemplate = Intent(context, activityClass)
return TaskStackBuilder.create(context)
.addNextIntentWithParentStack(clickIntentTemplate)
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}
}

View File

@@ -1,77 +0,0 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.widget
import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.Intent
import android.widget.RemoteViews
import android.widget.RemoteViewsService.RemoteViewsFactory
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper
import com.appttude.h_mal.atlas_weather.model.widget.InnerWidgetData
import kotlinx.coroutines.runBlocking
import org.kodein.di.KodeinAware
import org.kodein.di.LateInitKodein
import org.kodein.di.generic.instance
class MyWidgetRemoteViewsFactory(
private val context: Context,
val intent: Intent
) : RemoteViewsFactory{
private val TAG = "MyWidgetRemoteViewsFactory"
private val kodein = LateInitKodein()
private val helper : ServicesHelper by kodein.instance()
private var appWidgetId: Int? = 0
private var list: List<InnerWidgetData>? = null
init {
appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID)
kodein.baseKodein = (context.applicationContext as KodeinAware).kodein
}
override fun onCreate() {}
override fun onDataSetChanged() {
runBlocking {
list = helper.getWidgetInnerWeather()
}
}
override fun onDestroy() {}
override fun getCount(): Int = list?.size ?: 5
override fun getViewAt(i: Int): RemoteViews {
val rv = RemoteViews(context.packageName, R.layout.widget_item)
if (list.isNullOrEmpty()) return rv
list?.get(i)?.let {
rv.setTextViewText(R.id.widget_item_day, it.date)
rv.setImageViewBitmap(R.id.widget_item_image, it.icon)
rv.setTextViewText(R.id.widget_item_temp_high, it.highTemp)
rv.setOnClickFillInIntent(R.id.widget_item_layout, intent)
}
return rv
}
override fun getLoadingView(): RemoteViews {
return RemoteViews(context.packageName, R.layout.widget_item_loading)
}
override fun getViewTypeCount(): Int = 1
override fun getItemId(i: Int): Long = i.toLong()
override fun hasStableIds(): Boolean {
return true
}
}

View File

@@ -1,141 +0,0 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.widget
import android.Manifest
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.util.Log
import android.widget.RemoteViews
import androidx.core.app.ActivityCompat
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.atlasWeather.ui.MainActivity
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper
import com.appttude.h_mal.atlas_weather.model.widget.WidgetData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.kodein.di.KodeinAware
import org.kodein.di.LateInitKodein
import org.kodein.di.generic.instance
/**
* Implementation of App Widget functionality.
*/
private val TAG = NewAppWidget::class.java.simpleName
class NewAppWidget : BaseWidgetClass() {
private val kodein = LateInitKodein()
private val helper : ServicesHelper by kodein.instance()
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
kodein.baseKodein = (context.applicationContext as KodeinAware).kodein
// There may be multiple widgets active, so update all of them
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return
}
CoroutineScope(Dispatchers.IO).launch {
val results = helper.fetchData()
if (results) return@launch
val weatherWidgetCurrent = helper.getWidgetWeather()
withContext(Dispatchers.Main){
for (appWidgetId in appWidgetIds) {
val updatePendingIntent = createUpdatePendingIntent(context, appWidgetId)
val views = createRemoteView(context, R.layout.new_app_widget)
bindView(context, appWidgetId, views, updatePendingIntent, weatherWidgetCurrent)
}
super.onUpdate(context, appWidgetManager, appWidgetIds)
}
}
}
override fun onEnabled(context: Context) {
try {
val appWidgetManager = AppWidgetManager.getInstance(context)
val thisAppWidget = ComponentName(context.packageName, NewAppWidget::class.java.name)
val appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget)
onUpdate(context, appWidgetManager, appWidgetIds)
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widget_listview)
} catch (e: Exception) {
Log.e(TAG, "onEnabled: ", e)
}
}
override fun onDisabled(context: Context) {
// Enter relevant functionality for when the last widget is disabled
}
override fun onReceive(context: Context, intent: Intent) {
if (intent.action ==
AppWidgetManager.ACTION_APPWIDGET_UPDATE) {
val appWidgetManager = AppWidgetManager.getInstance(context)
val thisAppWidget = ComponentName(context.packageName, NewAppWidget::class.java.name)
val appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget)
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widget_listview)
}
super.onReceive(context, intent)
}
private fun createForecastListIntent(
context: Context,
appWidgetId: Int
): Intent {
return Intent(context, WidgetRemoteViewsService::class.java).apply {
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))
}
}
private fun bindView(
context: Context,
appWidgetId: Int,
views: RemoteViews,
updatePendingIntent: PendingIntent?,
weather: WidgetData?){
val appWidgetManager = AppWidgetManager.getInstance(context)
views.setInt(R.id.whole_widget_view, "setBackgroundColor", helper.getWidgetBackground())
weather?.let {
val intent = createForecastListIntent(
context,
appWidgetId
)
views.setRemoteAdapter(R.id.widget_listview, intent)
views.setTextViewText(R.id.widget_main_temp, it.currentTemp)
views.setTextViewText(R.id.widget_feel_temp, "°C")
views.setTextViewText(R.id.widget_current_location, it.location)
views.setImageViewResource(R.id.location_icon, R.drawable.location_flag)
// views.setImageViewBitmap(R.id.widget_current_icon, it.icon)
val clickPendingIntentTemplate = createClickingPendingIntent(context, MainActivity::class.java)
views.setPendingIntentTemplate(R.id.widget_listview, clickPendingIntentTemplate)
views.setOnClickPendingIntent(R.id.widget_current_icon, updatePendingIntent)
views.setOnClickPendingIntent(R.id.widget_current_location, updatePendingIntent)
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views)
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview)
return
}
Log.i(TAG, "onPostExecute: weather is empty")
views.setTextViewText(R.id.widget_current_location, "Refresh")
views.setImageViewResource(R.id.widget_current_icon, R.drawable.widget_error_icon)
views.setImageViewResource(R.id.location_icon, R.drawable.refreshing)
views.setOnClickPendingIntent(R.id.widget_current_icon, updatePendingIntent)
views.setOnClickPendingIntent(R.id.widget_current_location, updatePendingIntent)
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}

View File

@@ -1,10 +0,0 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.widget
import android.content.Intent
import android.widget.RemoteViewsService
class WidgetRemoteViewsService : RemoteViewsService() {
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
return MyWidgetRemoteViewsFactory(applicationContext, intent)
}
}

View File

@@ -1,15 +0,0 @@
package com.appttude.h_mal.atlas_weather.atlasWeather.widget
import android.app.Activity
import android.app.PendingIntent
import android.app.TaskStackBuilder
import android.content.Context
import android.content.Intent
fun <T: Activity> createClickingPendingIntent(context: Context, activityClass: Class<T>): PendingIntent {
val clickIntentTemplate = Intent(context, activityClass)
return TaskStackBuilder.create(context)
.addNextIntentWithParentStack(clickIntentTemplate)
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}

View File

@@ -1,5 +0,0 @@
package com.appttude.h_mal.ui
import com.appttude.h_mal.R
val tabs = setOf(R.id.nav_home, R.id.nav_world)

View File

@@ -8,21 +8,17 @@
<fragment
android:id="@+id/nav_home"
android:name="com.appttude.h_mal.atlas_weather.atlasWeather.ui.home.HomeFragment"
android:name="com.appttude.h_mal.atlas_weather.ui.home.HomeFragment"
android:label="Home"
tools:layout="@layout/fragment_home">
<action
android:id="@+id/action_homeFragment_to_furtherDetailsFragment"
app:destination="@id/furtherDetailsFragment"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_open_enter"
app:popExitAnim="@anim/fragment_open_exit" />
app:destination="@id/furtherDetailsFragment" />
</fragment>
<fragment
android:id="@+id/furtherDetailsFragment"
android:name="com.appttude.h_mal.atlas_weather.atlasWeather.ui.details.FurtherInfoFragment"
android:name="com.appttude.h_mal.atlas_weather.ui.details.FurtherInfoFragment"
android:label="Further Details">
<argument
android:name="forecast"
@@ -31,41 +27,29 @@
<fragment
android:id="@+id/nav_world"
android:name="com.appttude.h_mal.atlas_weather.atlasWeather.ui.world.WorldFragment"
android:name="com.appttude.h_mal.atlas_weather.ui.world.WorldFragment"
android:label="World"
tools:layout="@layout/fragment__two">
<action
android:id="@+id/action_worldFragment_to_addLocationFragment"
app:destination="@id/addLocationFragment"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_open_enter"
app:popExitAnim="@anim/fragment_open_exit" />
app:destination="@id/addLocationFragment"/>
<action
android:id="@+id/action_worldFragment_to_worldItemFragment"
app:destination="@id/worldItemFragment"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_open_enter"
app:popExitAnim="@anim/fragment_open_exit" />
app:destination="@id/worldItemFragment" />
</fragment>
<fragment
android:id="@+id/addLocationFragment"
android:name="com.appttude.h_mal.atlas_weather.atlasWeather.ui.world.AddLocationFragment"
android:name="com.appttude.h_mal.atlas_weather.ui.world.AddLocationFragment"
android:label="Add Weather Location"
tools:layout="@layout/activity_add_forecast" />
<fragment
android:id="@+id/worldItemFragment"
android:name="com.appttude.h_mal.atlas_weather.atlasWeather.ui.WorldItemFragment"
android:name="com.appttude.h_mal.atlas_weather.ui.WorldItemFragment"
android:label="Overview"
tools:layout="@layout/fragment_home">
<action
android:id="@+id/action_worldItemFragment_to_furtherDetailsFragment"
app:destination="@id/furtherDetailsFragment"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_open_enter"
app:popExitAnim="@anim/fragment_open_exit" />
app:destination="@id/furtherDetailsFragment" />
<argument
android:name="weatherDisplay"
app:argType="com.appttude.h_mal.atlas_weather.model.forecast.WeatherDisplay" />

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:configure="com.appttude.h_mal.ui.widget.WidgetLocationPermissionActivity"
android:configure="com.appttude.h_mal.atlas_weather.ui.widget.WidgetLocationPermissionActivity"
android:initialKeyguardLayout="@layout/weather_app_widget"
android:initialLayout="@layout/weather_app_widget"
android:minHeight="110.0dp"

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.appttude.h_mal">
package="com.appttude.h_mal.atlas_weather">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

View File

@@ -1,27 +0,0 @@
package com.appttude.h_mal.application
import com.appttude.h_mal.data.location.LocationProviderImpl
import com.appttude.h_mal.data.network.NetworkModule
import com.appttude.h_mal.data.network.WeatherApi
import com.appttude.h_mal.data.network.interceptors.NetworkConnectionInterceptor
import com.appttude.h_mal.data.network.interceptors.QueryParamsInterceptor
import com.appttude.h_mal.data.network.networkUtils.loggingInterceptor
import com.appttude.h_mal.data.room.AppDatabase
const val LOCATION_PERMISSION_REQUEST = 505
class AppClass : BaseAppClass() {
override fun createNetworkModule(): WeatherApi {
return NetworkModule().invoke<WeatherApi>(
NetworkConnectionInterceptor(this),
QueryParamsInterceptor(),
loggingInterceptor
) as WeatherApi
}
override fun createLocationModule() = LocationProviderImpl(this)
override fun createRoomDatabase(): AppDatabase = AppDatabase(this)
}

View File

@@ -0,0 +1,27 @@
package com.appttude.h_mal.atlas_weather.application
import com.appttude.h_mal.atlas_weather.data.location.LocationProviderImpl
import com.appttude.h_mal.atlas_weather.data.network.NetworkModule
import com.appttude.h_mal.atlas_weather.data.network.WeatherApi
import com.appttude.h_mal.atlas_weather.data.network.interceptors.NetworkConnectionInterceptor
import com.appttude.h_mal.atlas_weather.data.network.interceptors.QueryParamsInterceptor
import com.appttude.h_mal.atlas_weather.data.network.networkUtils.loggingInterceptor
import com.appttude.h_mal.atlas_weather.data.room.AppDatabase
const val LOCATION_PERMISSION_REQUEST = 505
class AppClass : BaseAppClass() {
override fun createNetworkModule(): WeatherApi {
return NetworkModule().invoke<WeatherApi>(
NetworkConnectionInterceptor(this),
QueryParamsInterceptor(),
loggingInterceptor
) as WeatherApi
}
override fun createLocationModule() = LocationProviderImpl(this)
override fun createRoomDatabase(): AppDatabase = AppDatabase(this)
}

View File

@@ -1,14 +1,14 @@
package com.appttude.h_mal.application
package com.appttude.h_mal.atlas_weather.application
import android.app.Application
import com.appttude.h_mal.data.location.LocationProvider
import com.appttude.h_mal.data.network.WeatherApi
import com.appttude.h_mal.data.prefs.PreferenceProvider
import com.appttude.h_mal.data.repository.RepositoryImpl
import com.appttude.h_mal.data.repository.SettingsRepositoryImpl
import com.appttude.h_mal.data.room.AppDatabase
import com.appttude.h_mal.helper.ServicesHelper
import com.appttude.h_mal.viewmodel.ApplicationViewModelFactory
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
import com.appttude.h_mal.atlas_weather.data.network.WeatherApi
import com.appttude.h_mal.atlas_weather.data.prefs.PreferenceProvider
import com.appttude.h_mal.atlas_weather.data.repository.RepositoryImpl
import com.appttude.h_mal.atlas_weather.data.repository.SettingsRepositoryImpl
import com.appttude.h_mal.atlas_weather.data.room.AppDatabase
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
import com.google.gson.Gson
import org.kodein.di.Kodein
import org.kodein.di.KodeinAware

View File

@@ -1,9 +1,9 @@
package com.appttude.h_mal.data.location
package com.appttude.h_mal.atlas_weather.data.location
import android.content.Context
import android.location.Location
import com.appttude.h_mal.BuildConfig
import com.appttude.h_mal.utils.createSuspend
import com.appttude.h_mal.atlas_weather.BuildConfig
import com.appttude.h_mal.atlas_weather.utils.createSuspend
import com.tomtom.online.sdk.search.OnlineSearchApi
import com.tomtom.online.sdk.search.data.common.Address
import com.tomtom.online.sdk.search.data.reversegeocoder.ReverseGeocoderSearchQueryBuilder

View File

@@ -1,6 +1,6 @@
package com.appttude.h_mal.data.location
package com.appttude.h_mal.atlas_weather.data.location
import com.appttude.h_mal.model.types.LocationType
import com.appttude.h_mal.atlas_weather.model.types.LocationType
interface LocationProvider {
suspend fun getCurrentLatLong(): Pair<Double, Double>

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.data.location
package com.appttude.h_mal.atlas_weather.data.location
import android.Manifest.permission.ACCESS_COARSE_LOCATION
import android.annotation.SuppressLint
@@ -8,7 +8,7 @@ import android.location.Location
import android.location.LocationManager
import android.os.HandlerThread
import androidx.annotation.RequiresPermission
import com.appttude.h_mal.model.types.LocationType
import com.appttude.h_mal.atlas_weather.model.types.LocationType
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
@@ -26,7 +26,7 @@ import kotlin.coroutines.suspendCoroutine
class LocationProviderImpl(
private val applicationContext: Context
) : LocationProvider, LocationHelper(applicationContext) {
) : com.appttude.h_mal.atlas_weather.data.location.LocationProvider, com.appttude.h_mal.atlas_weather.data.location.LocationHelper(applicationContext) {
private var locationManager =
applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
private val client = FusedLocationProviderClient(applicationContext)

View File

@@ -0,0 +1,3 @@
package com.appttude.h_mal.atlas_weather.data.network
interface Api

View File

@@ -1,7 +1,7 @@
package com.appttude.h_mal.data.network
package com.appttude.h_mal.atlas_weather.data.network
import com.appttude.h_mal.data.network.networkUtils.buildOkHttpClient
import com.appttude.h_mal.data.network.networkUtils.createRetrofit
import com.appttude.h_mal.atlas_weather.data.network.networkUtils.buildOkHttpClient
import com.appttude.h_mal.atlas_weather.data.network.networkUtils.createRetrofit
import okhttp3.Interceptor
open class BaseNetworkModule {

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.data.network
package com.appttude.h_mal.atlas_weather.data.network
class NetworkModule : BaseNetworkModule() {
override fun baseUrl(): String = "https://api.openweathermap.org/data/2.5/"

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.data.network
package com.appttude.h_mal.atlas_weather.data.network
import org.json.JSONException
import org.json.JSONObject

View File

@@ -1,6 +1,6 @@
package com.appttude.h_mal.data.network
package com.appttude.h_mal.atlas_weather.data.network
import com.appttude.h_mal.data.network.response.forecast.WeatherResponse
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.WeatherResponse
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Query

View File

@@ -1,7 +1,7 @@
package com.appttude.h_mal.data.network.interceptors
package com.appttude.h_mal.atlas_weather.data.network.interceptors
import android.content.Context
import com.appttude.h_mal.utils.isInternetAvailable
import com.appttude.h_mal.atlas_weather.utils.isInternetAvailable
import okhttp3.Interceptor
import java.io.IOException

View File

@@ -0,0 +1,5 @@
package com.appttude.h_mal.atlas_weather.data.network.interceptors
import okhttp3.Interceptor
interface NetworkInterceptor : Interceptor

View File

@@ -1,6 +1,6 @@
package com.appttude.h_mal.data.network.interceptors
package com.appttude.h_mal.atlas_weather.data.network.interceptors
import com.appttude.h_mal.BuildConfig
import com.appttude.h_mal.atlas_weather.BuildConfig
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response

View File

@@ -1,7 +1,6 @@
package com.appttude.h_mal.data.network.networkUtils
package com.appttude.h_mal.atlas_weather.data.network.networkUtils
import com.appttude.h_mal.data.network.interceptors.NetworkConnectionInterceptor
import com.appttude.h_mal.data.network.interceptors.NetworkInterceptor
import com.appttude.h_mal.atlas_weather.data.network.interceptors.NetworkInterceptor
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.data.network.response.forecast
package com.appttude.h_mal.atlas_weather.data.network.response.forecast
import com.google.gson.annotations.SerializedName

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.data.network.response.forecast
package com.appttude.h_mal.atlas_weather.data.network.response.forecast
import com.google.gson.annotations.SerializedName

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.data.network.response.forecast
package com.appttude.h_mal.atlas_weather.data.network.response.forecast
import com.google.gson.annotations.SerializedName

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.data.network.response.forecast
package com.appttude.h_mal.atlas_weather.data.network.response.forecast
import com.google.gson.annotations.SerializedName

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.data.network.response.forecast
package com.appttude.h_mal.atlas_weather.data.network.response.forecast
import com.google.gson.annotations.SerializedName

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.data.network.response.forecast
package com.appttude.h_mal.atlas_weather.data.network.response.forecast
import com.google.gson.annotations.SerializedName

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.data.network.response.forecast
package com.appttude.h_mal.atlas_weather.data.network.response.forecast
import com.google.gson.annotations.SerializedName

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.data.network.response.forecast
package com.appttude.h_mal.atlas_weather.data.network.response.forecast
import com.google.gson.annotations.SerializedName

View File

@@ -1,9 +1,9 @@
package com.appttude.h_mal.data.prefs
package com.appttude.h_mal.atlas_weather.data.prefs
import android.content.Context
import android.content.SharedPreferences
import androidx.preference.PreferenceManager
import com.appttude.h_mal.data.room.entity.CURRENT_LOCATION
import com.appttude.h_mal.atlas_weather.data.room.entity.CURRENT_LOCATION
/**
* Shared preferences to save & load last timestamp

View File

@@ -1,8 +1,8 @@
package com.appttude.h_mal.data.repository
package com.appttude.h_mal.atlas_weather.data.repository
import androidx.lifecycle.LiveData
import com.appttude.h_mal.data.network.response.forecast.WeatherResponse
import com.appttude.h_mal.data.room.entity.EntityItem
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.WeatherResponse
import com.appttude.h_mal.atlas_weather.data.room.entity.EntityItem
interface Repository {

View File

@@ -1,13 +1,13 @@
package com.appttude.h_mal.data.repository
package com.appttude.h_mal.atlas_weather.data.repository
import com.appttude.h_mal.data.network.ResponseUnwrap
import com.appttude.h_mal.data.network.WeatherApi
import com.appttude.h_mal.data.network.response.forecast.WeatherResponse
import com.appttude.h_mal.data.prefs.LOCATION_CONST
import com.appttude.h_mal.data.prefs.PreferenceProvider
import com.appttude.h_mal.data.room.AppDatabase
import com.appttude.h_mal.data.room.entity.EntityItem
import com.appttude.h_mal.utils.FALLBACK_TIME
import com.appttude.h_mal.atlas_weather.data.network.ResponseUnwrap
import com.appttude.h_mal.atlas_weather.data.network.WeatherApi
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.WeatherResponse
import com.appttude.h_mal.atlas_weather.data.prefs.LOCATION_CONST
import com.appttude.h_mal.atlas_weather.data.prefs.PreferenceProvider
import com.appttude.h_mal.atlas_weather.data.room.AppDatabase
import com.appttude.h_mal.atlas_weather.data.room.entity.EntityItem
import com.appttude.h_mal.atlas_weather.utils.FALLBACK_TIME
class RepositoryImpl(

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.data.repository
package com.appttude.h_mal.atlas_weather.data.repository
interface SettingsRepository {
fun isNotificationsEnabled(): Boolean

View File

@@ -1,6 +1,6 @@
package com.appttude.h_mal.data.repository
package com.appttude.h_mal.atlas_weather.data.repository
import com.appttude.h_mal.data.prefs.PreferenceProvider
import com.appttude.h_mal.atlas_weather.data.prefs.PreferenceProvider
class SettingsRepositoryImpl(
private val prefs: PreferenceProvider

View File

@@ -1,11 +1,11 @@
package com.appttude.h_mal.data.room
package com.appttude.h_mal.atlas_weather.data.room
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import com.appttude.h_mal.data.room.entity.EntityItem
import com.appttude.h_mal.atlas_weather.data.room.entity.EntityItem
@Database(
entities = [EntityItem::class],

View File

@@ -1,9 +1,9 @@
package com.appttude.h_mal.data.room
package com.appttude.h_mal.atlas_weather.data.room
import android.content.Context
import androidx.room.ProvidedTypeConverter
import androidx.room.TypeConverter
import com.appttude.h_mal.model.weather.FullWeather
import com.appttude.h_mal.atlas_weather.model.weather.FullWeather
import com.google.gson.Gson
import org.kodein.di.KodeinAware
import org.kodein.di.android.kodein

View File

@@ -1,12 +1,12 @@
package com.appttude.h_mal.data.room
package com.appttude.h_mal.atlas_weather.data.room
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.appttude.h_mal.data.room.entity.CURRENT_LOCATION
import com.appttude.h_mal.data.room.entity.EntityItem
import com.appttude.h_mal.atlas_weather.data.room.entity.CURRENT_LOCATION
import com.appttude.h_mal.atlas_weather.data.room.entity.EntityItem
@Dao
interface WeatherDao {

View File

@@ -1,8 +1,8 @@
package com.appttude.h_mal.data.room.entity
package com.appttude.h_mal.atlas_weather.data.room.entity
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.appttude.h_mal.model.weather.FullWeather
import com.appttude.h_mal.atlas_weather.model.weather.FullWeather
const val CURRENT_LOCATION = "CurrentLocation"

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.helper
package com.appttude.h_mal.atlas_weather.helper
import android.view.LayoutInflater
import android.view.ViewGroup

View File

@@ -1,21 +1,21 @@
package com.appttude.h_mal.helper
package com.appttude.h_mal.atlas_weather.helper
import android.Manifest
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.drawable.Drawable
import androidx.annotation.RequiresPermission
import com.appttude.h_mal.data.location.LocationProvider
import com.appttude.h_mal.data.repository.Repository
import com.appttude.h_mal.data.repository.SettingsRepository
import com.appttude.h_mal.data.room.entity.CURRENT_LOCATION
import com.appttude.h_mal.data.room.entity.EntityItem
import com.appttude.h_mal.model.weather.FullWeather
import com.appttude.h_mal.model.widget.InnerWidgetCellData
import com.appttude.h_mal.model.widget.InnerWidgetData
import com.appttude.h_mal.model.widget.WidgetData
import com.appttude.h_mal.model.widget.WidgetWeatherCollection
import com.appttude.h_mal.utils.toSmallDayName
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
import com.appttude.h_mal.atlas_weather.data.repository.Repository
import com.appttude.h_mal.atlas_weather.data.repository.SettingsRepository
import com.appttude.h_mal.atlas_weather.data.room.entity.CURRENT_LOCATION
import com.appttude.h_mal.atlas_weather.data.room.entity.EntityItem
import com.appttude.h_mal.atlas_weather.model.weather.FullWeather
import com.appttude.h_mal.atlas_weather.model.widget.InnerWidgetCellData
import com.appttude.h_mal.atlas_weather.model.widget.InnerWidgetData
import com.appttude.h_mal.atlas_weather.model.widget.WidgetData
import com.appttude.h_mal.atlas_weather.model.widget.WidgetWeatherCollection
import com.appttude.h_mal.atlas_weather.utils.toSmallDayName
import com.squareup.picasso.Picasso
import com.squareup.picasso.Target
import kotlinx.coroutines.Dispatchers

View File

@@ -0,0 +1,93 @@
package com.appttude.h_mal.atlas_weather.model.forecast
import android.os.Parcel
import android.os.Parcelable
import com.appttude.h_mal.atlas_weather.model.weather.DailyWeather
import com.appttude.h_mal.atlas_weather.utils.toDayName
import com.appttude.h_mal.atlas_weather.utils.toDayString
import com.appttude.h_mal.atlas_weather.utils.toTime
data class Forecast(
val date: String?,
val day: String?,
val condition: String?,
val weatherIcon: String?,
val mainTemp: String?,
val minorTemp: String?,
val averageTemp: String?,
val windText: String?,
val precipitation: String?,
val humidity: String?,
val uvi: String?,
val sunrise: String?,
val sunset: String?,
val cloud: String?
): Parcelable{
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString()
) {
}
constructor(dailyWeather: DailyWeather) : this(
dailyWeather.dt?.toDayString(),
dailyWeather.dt?.toDayName(),
dailyWeather.description,
dailyWeather.icon,
dailyWeather.max?.toInt().toString(),
dailyWeather.min?.toInt().toString(),
dailyWeather.average?.toInt().toString(),
dailyWeather.windSpeed?.toInt().toString(),
(dailyWeather.pop?.times(100))?.toInt().toString(),
dailyWeather.humidity?.toString(),
dailyWeather.uvi?.toInt().toString(),
dailyWeather.sunrise?.toTime(),
dailyWeather.sunset?.toTime(),
dailyWeather.clouds?.toString()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(date)
parcel.writeString(day)
parcel.writeString(condition)
parcel.writeString(weatherIcon)
parcel.writeString(mainTemp)
parcel.writeString(minorTemp)
parcel.writeString(averageTemp)
parcel.writeString(windText)
parcel.writeString(precipitation)
parcel.writeString(humidity)
parcel.writeString(uvi)
parcel.writeString(sunrise)
parcel.writeString(sunset)
parcel.writeString(cloud)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Forecast> {
override fun createFromParcel(parcel: Parcel): Forecast {
return Forecast(parcel)
}
override fun newArray(size: Int): Array<Forecast?> {
return arrayOfNulls(size)
}
}
}

View File

@@ -0,0 +1,97 @@
package com.appttude.h_mal.atlas_weather.model.forecast
import android.os.Parcel
import android.os.Parcelable
import com.appttude.h_mal.atlas_weather.data.room.entity.EntityItem
import com.appttude.h_mal.atlas_weather.model.weather.Hour
data class WeatherDisplay(
val averageTemp: Double?,
var unit: String?,
var location: String?,
val iconURL: String?,
val description: String?,
val hourly: List<Hour>?,
val forecast: List<Forecast>?,
val windSpeed: String?,
val windDirection: String?,
val precipitation: String?,
val humidity: String?,
val clouds: String?,
val lat: Double = 0.00,
val lon: Double = 0.00,
var displayName: String?
): Parcelable {
constructor(parcel: Parcel) : this(
parcel.readValue(Double::class.java.classLoader) as? Double,
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.createTypedArrayList(Hour),
parcel.createTypedArrayList(Forecast),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readDouble(),
parcel.readDouble(),
parcel.readString()
) {
}
constructor(entity: EntityItem) : this(
entity.weather.current?.temp,
entity.weather.temperatureUnit,
entity.id,
entity.weather.current?.icon,
entity.weather.current?.description,
entity.weather.hourly,
entity.weather.daily?.drop(1)?.map { Forecast(it) },
entity.weather.current?.windSpeed?.toString(),
entity.weather.current?.windDeg?.toString(),
entity.weather.daily?.get(0)?.pop?.times(100)?.toInt()?.toString(),
entity.weather.current?.humidity?.toString(),
entity.weather.current?.clouds?.toString(),
entity.weather.lat,
entity.weather.lon,
entity.weather.locationString
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeValue(averageTemp)
parcel.writeString(unit)
parcel.writeString(location)
parcel.writeString(iconURL)
parcel.writeString(description)
parcel.writeTypedList(hourly)
parcel.writeTypedList(forecast)
parcel.writeString(windSpeed)
parcel.writeString(windDirection)
parcel.writeString(precipitation)
parcel.writeString(humidity)
parcel.writeString(clouds)
parcel.writeDouble(lat)
parcel.writeDouble(lon)
parcel.writeString(displayName)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<WeatherDisplay> {
override fun createFromParcel(parcel: Parcel): WeatherDisplay {
return WeatherDisplay(parcel)
}
override fun newArray(size: Int): Array<WeatherDisplay?> {
return arrayOfNulls(size)
}
}
}

View File

@@ -0,0 +1,6 @@
package com.appttude.h_mal.atlas_weather.model.types
enum class LocationType{
City,
Town
}

View File

@@ -1,7 +1,7 @@
package com.appttude.h_mal.model.weather
package com.appttude.h_mal.atlas_weather.model.weather
import com.appttude.h_mal.data.network.response.forecast.Current
import com.appttude.h_mal.utils.generateIconUrlString
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.Current
import com.appttude.h_mal.atlas_weather.utils.generateIconUrlString
data class Current(
val dt: Int? = null,

View File

@@ -1,7 +1,7 @@
package com.appttude.h_mal.model.weather
package com.appttude.h_mal.atlas_weather.model.weather
import com.appttude.h_mal.data.network.response.forecast.DailyItem
import com.appttude.h_mal.utils.generateIconUrlString
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.DailyItem
import com.appttude.h_mal.atlas_weather.utils.generateIconUrlString
data class DailyWeather(

View File

@@ -1,6 +1,6 @@
package com.appttude.h_mal.model.weather
package com.appttude.h_mal.atlas_weather.model.weather
import com.appttude.h_mal.data.network.response.forecast.WeatherResponse
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.WeatherResponse
data class FullWeather(
val current: Current? = null,

View File

@@ -0,0 +1,47 @@
package com.appttude.h_mal.atlas_weather.model.weather
import android.os.Parcel
import android.os.Parcelable
import com.appttude.h_mal.atlas_weather.utils.generateIconUrlString
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.Hour as ForecastHour
data class Hour(
val dt: Int? = null,
val temp: Double? = null,
val icon: String? = null
): Parcelable {
constructor(parcel: Parcel) : this(
parcel.readValue(Int::class.java.classLoader) as? Int,
parcel.readValue(Double::class.java.classLoader) as? Double,
parcel.readString()
) {
}
constructor(hour: ForecastHour) : this(
hour.dt,
hour.temp,
generateIconUrlString(hour.weather?.getOrNull(0)?.icon)
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeValue(dt)
parcel.writeValue(temp)
parcel.writeString(icon)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Hour> {
override fun createFromParcel(parcel: Parcel): Hour {
return Hour(parcel)
}
override fun newArray(size: Int): Array<Hour?> {
return arrayOfNulls(size)
}
}
}

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.model.widget
package com.appttude.h_mal.atlas_weather.model.widget
import android.graphics.Bitmap

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.ui
package com.appttude.h_mal.atlas_weather.ui
import android.content.Intent
import android.os.Bundle
@@ -10,8 +10,7 @@ import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.appttude.h_mal.R
import com.appttude.h_mal.monoWeather.ui.settings.UnitSettingsActivity
import com.appttude.h_mal.atlas_weather.R
import com.google.android.material.bottomnavigation.BottomNavigationView
import kotlinx.android.synthetic.main.activity_main_navigation.*

View File

@@ -0,0 +1,3 @@
package com.appttude.h_mal.atlas_weather.utils
val FALLBACK_TIME: Long = 300000L

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.utils
package com.appttude.h_mal.atlas_weather.utils
/**
* Used with livedata<T> to make observation lifecycle aware

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.utils
package com.appttude.h_mal.atlas_weather.utils
import android.os.Parcel
import android.os.Parcelable

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.utils
package com.appttude.h_mal.atlas_weather.utils
fun printToLog(msg: String) {
println("widget monitoring: $msg")

View File

@@ -1,10 +1,10 @@
package com.appttude.h_mal.utils
package com.appttude.h_mal.atlas_weather.utils
import android.view.View
import androidx.fragment.app.Fragment
import androidx.navigation.NavDirections
import androidx.navigation.Navigation
import com.appttude.h_mal.R
import com.appttude.h_mal.atlas_weather.R
fun Fragment.navigateToFragment(newFragment: Fragment){
childFragmentManager.beginTransaction()

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.utils
package com.appttude.h_mal.atlas_weather.utils
import android.content.Context
import android.net.ConnectivityManager

Some files were not shown because too many files have changed in this diff Show More