Permissions playstore dialog (#22)

- Permissions dispatcher added
 - Updated to widget api 31+
 - circleci.yml updated
 - fastlane file fixed
This commit is contained in:
2023-08-13 17:11:05 +01:00
committed by GitHub
parent 1fa34764df
commit 247ff22115
23 changed files with 269 additions and 171 deletions

View File

@@ -45,21 +45,19 @@ commands:
default: "AtlasWeather"
package_suffix:
type: string
default: "atlas_weather"
default: "atlasWeather"
steps:
- android/start-emulator-and-run-tests:
post-emulator-launch-assemble-command: ./gradlew assemble<< parameters.flavour >>DebugAndroidTest
test-command: ./gradlew connected<< parameters.flavour >>DebugAndroidTest --continue
system-image: system-images;android-26;google_apis;x86
pull-data: true
pull-data-target: ~/app-data
# store screenshots for failed ui tests
- when:
condition: on_fail
steps:
- store_artifacts:
path: ~/app-data
destination: screenshots
path: app/build/outputs/connected_android_test_additional_output/monoWeatherDebugAndroidTest/connected
destination: connected_android_test
# store test reports
- store_artifacts:
path: app/build/reports/androidTests/connected
@@ -97,9 +95,6 @@ jobs:
flavour:
type: string
default: "AtlasWeather"
package_suffix:
type: string
default: "atlas_weather"
# These next lines define the Android machine image executor.
# See: https://circleci.com/docs/2.0/executor-types/
executor:
@@ -111,8 +106,27 @@ jobs:
- setup_repo
- run_tests:
flavour: << parameters.flavour >>
run_instrumentation_test:
# Parameters used for determining
parameters:
flavour:
type: string
default: "AtlasWeather"
package_suffix:
type: string
default: "atlasWeather"
# These next lines define the Android machine image executor.
# See: https://circleci.com/docs/2.0/executor-types/
executor:
name: android/android-machine
tag: 2023.05.1
# Add steps to the job
# See: https://circleci.com/docs/2.0/configuration-reference/#steps
steps:
- setup_repo
- run_ui_tests:
flavour: << parameters.flavour >>
package_suffix: << parameters.package_suffix >>
deploy-to-playstore:
parameters:
flavour:
@@ -137,11 +151,19 @@ workflows:
- build-and-test:
context: appttude
flavour: "MonoWeather"
package_suffix: "monoWeather"
filters:
branches:
ignore:
- main_atlas
- run_instrumentation_test:
context: appttude
flavour: "MonoWeather"
package_suffix: "monoWeather"
filters:
branches:
only:
- master
- main_mono
- deploy-to-playstore:
context: appttude
flavour: "MonoWeather"
@@ -156,11 +178,19 @@ workflows:
- build-and-test:
context: appttude
flavour: "AtlasWeather"
package_suffix: "atlas_weather"
filters:
branches:
ignore:
- main_mono
- run_instrumentation_test:
context: appttude
flavour: "AtlasWeather"
package_suffix: "atlasWeather"
filters:
branches:
only:
- master
- main_atlas
- deploy-to-playstore:
context: appttude
flavour: "AtlasWeather"

2
.gitignore vendored
View File

@@ -91,7 +91,7 @@ gen-external-apklibs
.idea/jarRepositorie
# Gem/fastlane
/Gemfile.lock
Gemfile.lock
/fastlane/report.xml
# Google play files
/google-play-key.json

View File

@@ -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}"
}

View File

@@ -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,35 +46,28 @@ class HomeFragment : BaseFragment<MainViewModel>(R.layout.fragment_home) {
swipe_refresh.apply {
setOnRefreshListener {
getPermissionResult(ACCESS_COARSE_LOCATION, LOCATION_PERMISSION_REQUEST) {
viewModel.fetchData()
showLocationWithPermissionCheck()
isRefreshing = true
}
}
}
recyclerAdapter = WeatherRecyclerAdapter(itemClick = {
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")
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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()
}
}

View File

@@ -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() {}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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()
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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,16 +42,12 @@ 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()
showLocationWithPermissionCheck()
isRefreshing = true
}
}
}
recyclerAdapter = WeatherRecyclerAdapter(itemClick = {
navigateToFurtherDetails(it)
@@ -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")
}
}

View File

@@ -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()
@@ -106,4 +98,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")
}
}

View File

@@ -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

View File

@@ -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

View 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>

0
gradlew vendored Normal file → Executable file
View File