mirror of
https://github.com/hmalik144/Weather-apps.git
synced 2025-12-10 02:05:20 +00:00
Merge branch 'master' into main_mono
# Conflicts: # .circleci/config.yml
This commit is contained in:
@@ -5,13 +5,20 @@ plugins {
|
||||
id 'kotlin-kapt'
|
||||
id 'androidx.navigation.safeargs'
|
||||
}
|
||||
|
||||
def relStorePassword = System.getenv("RELEASE_STORE_PASSWORD")
|
||||
def relKeyPassword = System.getenv("RELEASE_KEY_PASSWORD")
|
||||
def relKeyAlias = System.getenv("RELEASE_KEY_ALIAS")
|
||||
|
||||
def keystorePath = System.getenv('PWD') + "/app/keystore.jks"
|
||||
def keystore = file(keystorePath).exists() ? file(keystorePath) : null
|
||||
android {
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
compileSdkVersion 33
|
||||
defaultConfig {
|
||||
applicationId "com.appttude.h_mal.atlas_weather"
|
||||
compileSdk 33
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 33
|
||||
versionCode 5
|
||||
@@ -40,6 +47,14 @@ android {
|
||||
}
|
||||
|
||||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
storePassword relStorePassword
|
||||
keyPassword relKeyPassword
|
||||
keyAlias relKeyAlias
|
||||
storeFile keystore
|
||||
}
|
||||
}
|
||||
testOptions {
|
||||
unitTests {
|
||||
includeAndroidResources = true
|
||||
@@ -48,6 +63,7 @@ android {
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
@@ -99,6 +115,7 @@ dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'com.google.android.material:material:1.2.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'androidx.fragment:fragment:1.2.0'
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
|
||||
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
|
||||
@@ -187,4 +204,8 @@ dependencies {
|
||||
|
||||
/ * screenshot library * /
|
||||
androidTestImplementation 'tools.fastlane:screengrab:2.1.1'
|
||||
/ * Permissions dispatcher * /
|
||||
def dispatcher_ver = "4.9.2"
|
||||
implementation "com.github.permissions-dispatcher:permissionsdispatcher:${dispatcher_ver}"
|
||||
kapt "com.github.permissions-dispatcher:permissionsdispatcher-processor:${dispatcher_ver}"
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
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())
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
package com.appttude.h_mal.monoWeather.tests
|
||||
|
||||
|
||||
import com.appttude.h_mal.atlas_weather.BaseTest
|
||||
import com.appttude.h_mal.atlas_weather.ui.MainActivity
|
||||
import com.appttude.h_mal.atlas_weather.utils.Stubs
|
||||
import com.appttude.h_mal.monoWeather.MonoBaseTest
|
||||
import com.appttude.h_mal.monoWeather.robot.weatherScreen
|
||||
import org.junit.Test
|
||||
|
||||
class HomePageNoDataUITest : MonoBaseTest() {
|
||||
class HomePageNoDataUITest : BaseTest<MainActivity>(MainActivity::class.java) {
|
||||
|
||||
override fun beforeLaunch() {
|
||||
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.InvalidKey, 400)
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package com.appttude.h_mal.monoWeather.tests
|
||||
|
||||
|
||||
import com.appttude.h_mal.atlas_weather.BaseTest
|
||||
import com.appttude.h_mal.atlas_weather.ui.MainActivity
|
||||
import com.appttude.h_mal.atlas_weather.utils.Stubs
|
||||
import com.appttude.h_mal.monoWeather.MonoBaseTest
|
||||
import com.appttude.h_mal.monoWeather.robot.weatherScreen
|
||||
import org.junit.Test
|
||||
|
||||
class HomePageUITest : MonoBaseTest() {
|
||||
class HomePageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
|
||||
|
||||
override fun beforeLaunch() {
|
||||
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Metric)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package com.appttude.h_mal.monoWeather.tests
|
||||
|
||||
|
||||
import com.appttude.h_mal.atlas_weather.BaseTest
|
||||
import com.appttude.h_mal.atlas_weather.ui.MainActivity
|
||||
import com.appttude.h_mal.atlas_weather.utils.Stubs
|
||||
import com.appttude.h_mal.monoWeather.MonoBaseTest
|
||||
import com.appttude.h_mal.monoWeather.robot.ContainerRobot.Tab.WORLD
|
||||
import com.appttude.h_mal.monoWeather.robot.addLocation
|
||||
import com.appttude.h_mal.monoWeather.robot.container
|
||||
@@ -10,7 +11,7 @@ import com.appttude.h_mal.monoWeather.robot.weatherScreen
|
||||
import com.appttude.h_mal.monoWeather.robot.world
|
||||
import org.junit.Test
|
||||
|
||||
class WorldPageUITest : MonoBaseTest() {
|
||||
class WorldPageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
|
||||
|
||||
override fun beforeLaunch() {
|
||||
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Metric)
|
||||
|
||||
@@ -13,21 +13,31 @@ import androidx.navigation.ui.onNavDestinationSelected
|
||||
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.base.BaseFragment
|
||||
import com.appttude.h_mal.atlas_weather.model.forecast.Forecast
|
||||
import com.appttude.h_mal.atlas_weather.model.forecast.WeatherDisplay
|
||||
import com.appttude.h_mal.atlas_weather.ui.BaseFragment
|
||||
import com.appttude.h_mal.atlas_weather.ui.dialog.PermissionsDeclarationDialog
|
||||
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.MainViewModel
|
||||
import kotlinx.android.synthetic.main.fragment_home.*
|
||||
import permissions.dispatcher.NeedsPermission
|
||||
import permissions.dispatcher.OnNeverAskAgain
|
||||
import permissions.dispatcher.OnPermissionDenied
|
||||
import permissions.dispatcher.OnShowRationale
|
||||
import permissions.dispatcher.PermissionRequest
|
||||
import permissions.dispatcher.RuntimePermissions
|
||||
|
||||
|
||||
/**
|
||||
* A simple [Fragment] subclass.
|
||||
* create an instance of this fragment.
|
||||
*/
|
||||
@RuntimePermissions
|
||||
class HomeFragment : BaseFragment<MainViewModel>(R.layout.fragment_home) {
|
||||
private lateinit var recyclerAdapter: WeatherRecyclerAdapter
|
||||
|
||||
lateinit var recyclerAdapter: WeatherRecyclerAdapter
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
@@ -36,10 +46,8 @@ class HomeFragment : BaseFragment<MainViewModel>(R.layout.fragment_home) {
|
||||
|
||||
swipe_refresh.apply {
|
||||
setOnRefreshListener {
|
||||
getPermissionResult(ACCESS_COARSE_LOCATION, LOCATION_PERMISSION_REQUEST) {
|
||||
viewModel.fetchData()
|
||||
isRefreshing = true
|
||||
}
|
||||
showLocationWithPermissionCheck()
|
||||
isRefreshing = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,24 +55,19 @@ class HomeFragment : BaseFragment<MainViewModel>(R.layout.fragment_home) {
|
||||
navigateToFurtherDetails(it)
|
||||
})
|
||||
|
||||
forecast_listview.apply {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
adapter = recyclerAdapter
|
||||
}
|
||||
forecast_listview.adapter = recyclerAdapter
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
getPermissionResult(ACCESS_COARSE_LOCATION, LOCATION_PERMISSION_REQUEST) {
|
||||
viewModel.fetchData()
|
||||
}
|
||||
showLocationWithPermissionCheck()
|
||||
}
|
||||
|
||||
override fun onSuccess(data: Any?) {
|
||||
super.onSuccess(data)
|
||||
swipe_refresh.isRefreshing = false
|
||||
|
||||
if (data is WeatherDisplay) {
|
||||
recyclerAdapter.addCurrent(data)
|
||||
}
|
||||
@@ -75,14 +78,8 @@ class HomeFragment : BaseFragment<MainViewModel>(R.layout.fragment_home) {
|
||||
swipe_refresh.isRefreshing = false
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
override fun permissionsGranted() {
|
||||
viewModel.fetchData()
|
||||
}
|
||||
|
||||
private fun navigateToFurtherDetails(forecast: Forecast) {
|
||||
val directions = HomeFragmentDirections
|
||||
.actionHomeFragmentToFurtherDetailsFragment(forecast)
|
||||
val directions = HomeFragmentDirections.actionHomeFragmentToFurtherDetailsFragment(forecast)
|
||||
navigateTo(directions)
|
||||
}
|
||||
|
||||
@@ -95,4 +92,35 @@ class HomeFragment : BaseFragment<MainViewModel>(R.layout.fragment_home) {
|
||||
val navController = findNavController(requireActivity(), R.id.container)
|
||||
return item.onNavDestinationSelected(navController) || super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
// NOTE: delegate the permission handling to generated method
|
||||
onRequestPermissionsResult(requestCode, grantResults)
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@NeedsPermission(ACCESS_COARSE_LOCATION)
|
||||
fun showLocation() {
|
||||
viewModel.fetchData()
|
||||
}
|
||||
|
||||
@OnShowRationale(ACCESS_COARSE_LOCATION)
|
||||
fun showRationaleForLocation(request: PermissionRequest) {
|
||||
PermissionsDeclarationDialog(requireContext()).showDialog({
|
||||
request.proceed()
|
||||
}, {
|
||||
request.cancel()
|
||||
})
|
||||
}
|
||||
|
||||
@OnPermissionDenied(ACCESS_COARSE_LOCATION)
|
||||
fun onLocationDenied() {
|
||||
displayToast("Location permissions have been denied")
|
||||
}
|
||||
|
||||
@OnNeverAskAgain(ACCESS_COARSE_LOCATION)
|
||||
fun onLocationNeverAskAgain() {
|
||||
displayToast("Location permissions have been to never ask again")
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package com.appttude.h_mal.atlas_weather.ui.world
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.appttude.h_mal.atlas_weather.R
|
||||
import com.appttude.h_mal.atlas_weather.ui.BaseFragment
|
||||
import com.appttude.h_mal.atlas_weather.base.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.WorldViewModel
|
||||
|
||||
@@ -5,8 +5,8 @@ import android.view.View
|
||||
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.base.BaseFragment
|
||||
import com.appttude.h_mal.atlas_weather.model.forecast.WeatherDisplay
|
||||
import com.appttude.h_mal.atlas_weather.ui.BaseFragment
|
||||
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
||||
import kotlinx.android.synthetic.atlasWeather.fragment_add_location.floatingActionButton
|
||||
|
||||
@@ -1,29 +1,22 @@
|
||||
package com.appttude.h_mal.atlas_weather.base
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup.LayoutParams
|
||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||
import android.view.ViewGroup.inflate
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.ViewModelLazy
|
||||
import com.appttude.h_mal.atlas_weather.R
|
||||
import com.appttude.h_mal.atlas_weather.helper.GenericsHelper.getGenericClassAt
|
||||
import com.appttude.h_mal.atlas_weather.model.ViewState
|
||||
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
||||
import com.appttude.h_mal.atlas_weather.utils.hide
|
||||
import com.appttude.h_mal.atlas_weather.utils.show
|
||||
import com.appttude.h_mal.atlas_weather.utils.triggerAnimation
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.baseViewModels.BaseViewModel
|
||||
import org.kodein.di.KodeinAware
|
||||
import org.kodein.di.android.kodein
|
||||
import org.kodein.di.generic.instance
|
||||
|
||||
abstract class BaseActivity : AppCompatActivity(), KodeinAware {
|
||||
|
||||
private lateinit var loadingView: View
|
||||
private var loadingView: View? = null
|
||||
|
||||
override val kodein by kodein()
|
||||
|
||||
@@ -36,9 +29,9 @@ abstract class BaseActivity : AppCompatActivity(), KodeinAware {
|
||||
*/
|
||||
private fun instantiateLoadingView() {
|
||||
loadingView = inflate(this, R.layout.progress_layout, null)
|
||||
loadingView.setOnClickListener(null)
|
||||
loadingView?.setOnClickListener(null)
|
||||
addContentView(loadingView, LayoutParams(MATCH_PARENT, MATCH_PARENT))
|
||||
loadingView.hide()
|
||||
loadingView?.hide()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
@@ -55,14 +48,14 @@ abstract class BaseActivity : AppCompatActivity(), KodeinAware {
|
||||
* Called in case of success or some data emitted from the liveData in viewModel
|
||||
*/
|
||||
open fun onStarted() {
|
||||
loadingView.fadeIn()
|
||||
loadingView?.fadeIn()
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in case of success or some data emitted from the liveData in viewModel
|
||||
*/
|
||||
open fun onSuccess(data: Any?) {
|
||||
loadingView.fadeOut()
|
||||
loadingView?.fadeOut()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,7 +63,7 @@ abstract class BaseActivity : AppCompatActivity(), KodeinAware {
|
||||
*/
|
||||
open fun onFailure(error: Any?) {
|
||||
if (error is String) displayToast(error)
|
||||
loadingView.fadeOut()
|
||||
loadingView?.fadeOut()
|
||||
}
|
||||
|
||||
private fun View.fadeIn() = apply {
|
||||
@@ -85,7 +78,7 @@ abstract class BaseActivity : AppCompatActivity(), KodeinAware {
|
||||
|
||||
|
||||
override fun onBackPressed() {
|
||||
loadingView.hide()
|
||||
loadingView?.hide()
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,14 @@
|
||||
package com.appttude.h_mal.atlas_weather.ui
|
||||
package com.appttude.h_mal.atlas_weather.base
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.createViewModelLazy
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import com.appttude.h_mal.atlas_weather.application.LOCATION_PERMISSION_REQUEST
|
||||
import com.appttude.h_mal.atlas_weather.base.BaseActivity
|
||||
import com.appttude.h_mal.atlas_weather.base.baseViewModels.BaseViewModel
|
||||
import com.appttude.h_mal.atlas_weather.helper.GenericsHelper.getGenericClassAt
|
||||
import com.appttude.h_mal.atlas_weather.model.ViewState
|
||||
import com.appttude.h_mal.atlas_weather.utils.Event
|
||||
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.baseViewModels.BaseViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.kodein.di.KodeinAware
|
||||
import org.kodein.di.android.x.kodein
|
||||
import org.kodein.di.generic.instance
|
||||
@@ -32,7 +20,7 @@ abstract class BaseFragment<V : BaseViewModel>(@LayoutRes contentLayoutId: Int)
|
||||
KodeinAware {
|
||||
|
||||
override val kodein by kodein()
|
||||
val factory by instance<ApplicationViewModelFactory>()
|
||||
private val factory by instance<ApplicationViewModelFactory>()
|
||||
|
||||
val viewModel: V by getFragmentViewModel()
|
||||
|
||||
@@ -47,7 +35,6 @@ abstract class BaseFragment<V : BaseViewModel>(@LayoutRes contentLayoutId: Int)
|
||||
shortAnimationDuration = resources.getInteger(android.R.integer.config_shortAnimTime)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
mActivity = activity as BaseActivity
|
||||
@@ -84,53 +71,4 @@ abstract class BaseFragment<V : BaseViewModel>(@LayoutRes contentLayoutId: Int)
|
||||
open fun onFailure(error: Any?) {
|
||||
mActivity?.onFailure(error)
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a permission for
|
||||
* @param permission with
|
||||
* @param permissionCode
|
||||
* Callback if is already permission granted
|
||||
* @param permissionGranted
|
||||
*/
|
||||
fun getPermissionResult(
|
||||
permission: String,
|
||||
permissionCode: Int,
|
||||
permissionGranted: () -> Unit
|
||||
) {
|
||||
if (ActivityCompat.checkSelfPermission(
|
||||
requireContext(),
|
||||
permission
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
requestPermissions(arrayOf(permission), permissionCode)
|
||||
return
|
||||
} else {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
permissionGranted.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<String?>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (requestCode == LOCATION_PERMISSION_REQUEST) {
|
||||
if (grantResults.isNotEmpty() &&
|
||||
grantResults[0] == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
permissionsGranted()
|
||||
displayToast("Permission granted")
|
||||
} else {
|
||||
permissionsRefused()
|
||||
displayToast("Permission denied")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open fun permissionsGranted() {}
|
||||
open fun permissionsRefused() {}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.appttude.h_mal.atlas_weather.viewmodel.baseViewModels
|
||||
package com.appttude.h_mal.atlas_weather.base.baseViewModels
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.appttude.h_mal.atlas_weather.viewmodel.baseViewModels
|
||||
package com.appttude.h_mal.atlas_weather.base.baseViewModels
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.WeatherResponse
|
||||
import com.appttude.h_mal.atlas_weather.data.room.entity.EntityItem
|
||||
import com.appttude.h_mal.atlas_weather.model.weather.FullWeather
|
||||
@@ -44,6 +44,8 @@ class PreferenceProvider(
|
||||
preference.edit().putBoolean("FIRST_TIME_RUN", false).apply()
|
||||
}
|
||||
|
||||
fun getFirstTimeRun() = preference.getBoolean("FIRST_TIME_RUN", false)
|
||||
|
||||
fun isWidgetBackground(): Boolean {
|
||||
return preference.getBoolean("widget_black_background", false)
|
||||
}
|
||||
|
||||
@@ -3,5 +3,6 @@ package com.appttude.h_mal.atlas_weather.data.repository
|
||||
interface SettingsRepository {
|
||||
fun isNotificationsEnabled(): Boolean
|
||||
fun setFirstTime()
|
||||
fun getFirstTime(): Boolean
|
||||
fun isBlackBackground(): Boolean
|
||||
}
|
||||
@@ -9,6 +9,7 @@ class SettingsRepositoryImpl(
|
||||
override fun isNotificationsEnabled(): Boolean = prefs.isNotificationsEnabled()
|
||||
|
||||
override fun setFirstTime() = prefs.setFirstTimeRun()
|
||||
override fun getFirstTime(): Boolean = prefs.getFirstTimeRun()
|
||||
|
||||
override fun isBlackBackground() = prefs.isWidgetBackground()
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import com.appttude.h_mal.atlas_weather.data.repository.Repository
|
||||
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.forecast.WeatherDisplay
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.baseViewModels.WeatherViewModel
|
||||
import com.appttude.h_mal.atlas_weather.base.baseViewModels.WeatherViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -6,7 +6,7 @@ import com.appttude.h_mal.atlas_weather.data.repository.Repository
|
||||
import com.appttude.h_mal.atlas_weather.data.room.entity.EntityItem
|
||||
import com.appttude.h_mal.atlas_weather.model.forecast.WeatherDisplay
|
||||
import com.appttude.h_mal.atlas_weather.model.types.LocationType
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.baseViewModels.WeatherViewModel
|
||||
import com.appttude.h_mal.atlas_weather.base.baseViewModels.WeatherViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -6,7 +6,7 @@ import android.view.View
|
||||
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.ui.BaseFragment
|
||||
import com.appttude.h_mal.atlas_weather.base.BaseFragment
|
||||
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
||||
import com.appttude.h_mal.monoWeather.ui.home.adapter.WeatherRecyclerAdapter
|
||||
|
||||
@@ -11,24 +11,30 @@ import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.Navigation.findNavController
|
||||
import androidx.navigation.ui.onNavDestinationSelected
|
||||
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.base.BaseFragment
|
||||
import com.appttude.h_mal.atlas_weather.model.forecast.Forecast
|
||||
import com.appttude.h_mal.atlas_weather.model.forecast.WeatherDisplay
|
||||
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.MainViewModel
|
||||
import com.appttude.h_mal.monoWeather.dialog.PermissionsDeclarationDialog
|
||||
import com.appttude.h_mal.atlas_weather.ui.BaseFragment
|
||||
import com.appttude.h_mal.monoWeather.ui.home.adapter.WeatherRecyclerAdapter
|
||||
import kotlinx.android.synthetic.main.fragment_home.*
|
||||
import permissions.dispatcher.NeedsPermission
|
||||
import permissions.dispatcher.OnNeverAskAgain
|
||||
import permissions.dispatcher.OnPermissionDenied
|
||||
import permissions.dispatcher.OnShowRationale
|
||||
import permissions.dispatcher.PermissionRequest
|
||||
import permissions.dispatcher.RuntimePermissions
|
||||
|
||||
|
||||
/**
|
||||
* A simple [Fragment] subclass.
|
||||
* create an instance of this fragment.
|
||||
*/
|
||||
@RuntimePermissions
|
||||
class HomeFragment : BaseFragment<MainViewModel>(R.layout.fragment_home) {
|
||||
|
||||
lateinit var dialog: PermissionsDeclarationDialog
|
||||
lateinit var recyclerAdapter: WeatherRecyclerAdapter
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@@ -36,14 +42,10 @@ class HomeFragment : BaseFragment<MainViewModel>(R.layout.fragment_home) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
|
||||
dialog = PermissionsDeclarationDialog(requireContext())
|
||||
|
||||
swipe_refresh.apply {
|
||||
setOnRefreshListener {
|
||||
getPermissionResult(ACCESS_COARSE_LOCATION, LOCATION_PERMISSION_REQUEST) {
|
||||
viewModel.fetchData()
|
||||
isRefreshing = true
|
||||
}
|
||||
showLocationWithPermissionCheck()
|
||||
isRefreshing = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,16 +59,7 @@ class HomeFragment : BaseFragment<MainViewModel>(R.layout.fragment_home) {
|
||||
@SuppressLint("MissingPermission")
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
dialog.showDialog(agreeCallback = {
|
||||
getPermissionResult(ACCESS_COARSE_LOCATION, LOCATION_PERMISSION_REQUEST) {
|
||||
viewModel.fetchData()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
dialog.dismiss()
|
||||
showLocationWithPermissionCheck()
|
||||
}
|
||||
|
||||
override fun onSuccess(data: Any?) {
|
||||
@@ -83,14 +76,8 @@ class HomeFragment : BaseFragment<MainViewModel>(R.layout.fragment_home) {
|
||||
swipe_refresh.isRefreshing = false
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
override fun permissionsGranted() {
|
||||
viewModel.fetchData()
|
||||
}
|
||||
|
||||
private fun navigateToFurtherDetails(forecast: Forecast) {
|
||||
val directions = HomeFragmentDirections
|
||||
.actionHomeFragmentToFurtherDetailsFragment(forecast)
|
||||
val directions = HomeFragmentDirections.actionHomeFragmentToFurtherDetailsFragment(forecast)
|
||||
navigateTo(directions)
|
||||
}
|
||||
|
||||
@@ -103,4 +90,35 @@ class HomeFragment : BaseFragment<MainViewModel>(R.layout.fragment_home) {
|
||||
val navController = findNavController(requireActivity(), R.id.container)
|
||||
return item.onNavDestinationSelected(navController) || super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
// NOTE: delegate the permission handling to generated method
|
||||
onRequestPermissionsResult(requestCode, grantResults)
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@NeedsPermission(ACCESS_COARSE_LOCATION)
|
||||
fun showLocation() {
|
||||
viewModel.fetchData()
|
||||
}
|
||||
|
||||
@OnShowRationale(ACCESS_COARSE_LOCATION)
|
||||
fun showRationaleForLocation(request: PermissionRequest) {
|
||||
PermissionsDeclarationDialog(requireContext()).showDialog({
|
||||
request.proceed()
|
||||
}, {
|
||||
request.cancel()
|
||||
})
|
||||
}
|
||||
|
||||
@OnPermissionDenied(ACCESS_COARSE_LOCATION)
|
||||
fun onLocationDenied() {
|
||||
displayToast("Location permissions have been denied")
|
||||
}
|
||||
|
||||
@OnNeverAskAgain(ACCESS_COARSE_LOCATION)
|
||||
fun onLocationNeverAskAgain() {
|
||||
displayToast("Location permissions have been to never ask again")
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.appttude.h_mal.monoWeather.ui.widget
|
||||
|
||||
import android.Manifest.permission.ACCESS_BACKGROUND_LOCATION
|
||||
import android.Manifest.permission.ACCESS_COARSE_LOCATION
|
||||
import android.app.Activity
|
||||
import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||
@@ -7,20 +8,26 @@ import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID
|
||||
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS
|
||||
import android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat.checkSelfPermission
|
||||
import com.appttude.h_mal.atlas_weather.R
|
||||
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
||||
import com.appttude.h_mal.monoWeather.dialog.DeclarationBuilder
|
||||
import com.appttude.h_mal.monoWeather.dialog.PermissionsDeclarationDialog
|
||||
import kotlinx.android.synthetic.monoWeather.permissions_declaration_dialog.cancel
|
||||
import kotlinx.android.synthetic.monoWeather.permissions_declaration_dialog.submit
|
||||
import permissions.dispatcher.NeedsPermission
|
||||
import permissions.dispatcher.OnNeverAskAgain
|
||||
import permissions.dispatcher.OnPermissionDenied
|
||||
import permissions.dispatcher.OnShowRationale
|
||||
import permissions.dispatcher.PermissionRequest
|
||||
import permissions.dispatcher.RuntimePermissions
|
||||
|
||||
const val PERMISSION_CODE = 401
|
||||
|
||||
@RuntimePermissions
|
||||
class WidgetLocationPermissionActivity : AppCompatActivity(), DeclarationBuilder {
|
||||
override val link: String = "https://sites.google.com/view/hmaldev/home/monochrome"
|
||||
override var message: String = ""
|
||||
@@ -54,31 +61,16 @@ class WidgetLocationPermissionActivity : AppCompatActivity(), DeclarationBuilder
|
||||
}
|
||||
|
||||
submit.setOnClickListener {
|
||||
if (checkSelfPermission(this, ACCESS_COARSE_LOCATION) != PERMISSION_GRANTED) {
|
||||
requestPermissions(arrayOf(ACCESS_COARSE_LOCATION), PERMISSION_CODE)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
showBackgroundLocationWithPermissionCheck()
|
||||
} else {
|
||||
submitWidget()
|
||||
showLocationWithPermissionCheck()
|
||||
}
|
||||
}
|
||||
|
||||
cancel.setOnClickListener { finish() }
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<out String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (requestCode == PERMISSION_CODE) {
|
||||
if (grantResults.isNotEmpty() && grantResults[0] == PERMISSION_GRANTED) {
|
||||
submitWidget()
|
||||
} else {
|
||||
displayToast("Location Permission denied")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun submitWidget() {
|
||||
sendUpdateIntent()
|
||||
finishCurrencyWidgetActivity()
|
||||
@@ -86,8 +78,7 @@ class WidgetLocationPermissionActivity : AppCompatActivity(), DeclarationBuilder
|
||||
|
||||
private fun finishCurrencyWidgetActivity() {
|
||||
// Make sure we pass back the original appWidgetId
|
||||
val resultValue = intent
|
||||
resultValue.putExtra(EXTRA_APPWIDGET_ID, mAppWidgetId)
|
||||
val resultValue = Intent().putExtra(EXTRA_APPWIDGET_ID, mAppWidgetId)
|
||||
setResult(Activity.RESULT_OK, resultValue)
|
||||
finish()
|
||||
}
|
||||
@@ -106,4 +97,66 @@ class WidgetLocationPermissionActivity : AppCompatActivity(), DeclarationBuilder
|
||||
sendBroadcast(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
// NOTE: delegate the permission handling to generated method
|
||||
onRequestPermissionsResult(requestCode, grantResults)
|
||||
}
|
||||
|
||||
@NeedsPermission(ACCESS_COARSE_LOCATION)
|
||||
fun showLocation() {
|
||||
submitWidget()
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@NeedsPermission(ACCESS_BACKGROUND_LOCATION)
|
||||
fun showBackgroundLocation() {
|
||||
submitWidget()
|
||||
}
|
||||
|
||||
@OnShowRationale(ACCESS_COARSE_LOCATION)
|
||||
fun showRationaleForLocation(request: PermissionRequest) {
|
||||
PermissionsDeclarationDialog(this).showDialog({
|
||||
request.proceed()
|
||||
}, {
|
||||
request.cancel()
|
||||
})
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@OnShowRationale(ACCESS_BACKGROUND_LOCATION)
|
||||
fun showRationaleForBackgroundLocation(request: PermissionRequest) {
|
||||
PermissionsDeclarationDialog(this).showDialog({
|
||||
request.proceed()
|
||||
}, {
|
||||
request.cancel()
|
||||
})
|
||||
}
|
||||
|
||||
@OnPermissionDenied(ACCESS_COARSE_LOCATION)
|
||||
fun onLocationDenied() {
|
||||
displayToast("Location permissions have been denied")
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@OnPermissionDenied(ACCESS_BACKGROUND_LOCATION)
|
||||
fun onBackgroundLocationDenied() {
|
||||
displayToast("Background Location permissions have been denied")
|
||||
}
|
||||
|
||||
@OnNeverAskAgain(ACCESS_COARSE_LOCATION)
|
||||
fun onLocationNeverAskAgain() {
|
||||
displayToast("Location permissions have been to never ask again")
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@OnNeverAskAgain(ACCESS_BACKGROUND_LOCATION)
|
||||
fun onBackgroundLocationNeverAskAgain() {
|
||||
displayToast("Background Location permissions have been to never ask again")
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package com.appttude.h_mal.monoWeather.ui.world
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.appttude.h_mal.atlas_weather.R
|
||||
import com.appttude.h_mal.atlas_weather.ui.BaseFragment
|
||||
import com.appttude.h_mal.atlas_weather.base.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.utils.hideKeyboard
|
||||
|
||||
@@ -6,7 +6,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.ui.BaseFragment
|
||||
import com.appttude.h_mal.atlas_weather.base.BaseFragment
|
||||
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
||||
import com.appttude.h_mal.monoWeather.ui.world.WorldFragmentDirections.actionWorldFragmentToWorldItemFragment
|
||||
|
||||
13
app/src/monoWeather/res/xml-v31/new_app_widget_info.xml
Normal file
13
app/src/monoWeather/res/xml-v31/new_app_widget_info.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:configure="com.appttude.h_mal.monoWeather.ui.widget.WidgetLocationPermissionActivity"
|
||||
android:initialKeyguardLayout="@layout/weather_app_widget"
|
||||
android:initialLayout="@layout/weather_app_widget"
|
||||
android:targetCellWidth="5"
|
||||
android:targetCellHeight="1"
|
||||
android:previewImage="@drawable/widget_screenshot"
|
||||
android:resizeMode="vertical|horizontal"
|
||||
android:updatePeriodMillis="1800000"
|
||||
android:widgetCategory="home_screen">
|
||||
|
||||
</appwidget-provider>
|
||||
Reference in New Issue
Block a user