mirror of
https://github.com/hmalik144/Weather-apps.git
synced 2026-03-18 15:36:04 +00:00
Refactor flavours (#17)
- Fastlane completed - Circleci config completed - Flavours build completed
This commit is contained in:
@@ -1,142 +0,0 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
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.viewModels
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import com.appttude.h_mal.atlas_weather.application.LOCATION_PERMISSION_REQUEST
|
||||
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.utils.hide
|
||||
import com.appttude.h_mal.atlas_weather.utils.show
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
||||
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
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
abstract class BaseFragment(@LayoutRes contentLayoutId: Int) : Fragment(contentLayoutId), KodeinAware {
|
||||
|
||||
override val kodein by kodein()
|
||||
val factory by instance<ApplicationViewModelFactory>()
|
||||
|
||||
inline fun <reified VM : ViewModel> getFragmentViewModel(): Lazy<VM> = viewModels { factory }
|
||||
|
||||
private var shortAnimationDuration by Delegates.notNull<Int>()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
shortAnimationDuration = resources.getInteger(android.R.integer.config_shortAnimTime)
|
||||
}
|
||||
|
||||
// toggle visibility of progress spinner while async operations are taking place
|
||||
fun progressBarStateObserver(progressBar: View) = Observer<Event<Boolean>> {
|
||||
when (it.getContentIfNotHandled()) {
|
||||
true -> progressBar.fadeIn()
|
||||
false -> progressBar.fadeOut()
|
||||
}
|
||||
}
|
||||
|
||||
// display a toast when operation fails
|
||||
fun errorObserver() = Observer<Event<String>> {
|
||||
it.getContentIfNotHandled()?.let { message ->
|
||||
displayToast(message)
|
||||
}
|
||||
}
|
||||
|
||||
fun refreshObserver(refresher: SwipeRefreshLayout) = Observer<Event<Boolean>> {
|
||||
refresher.isRefreshing = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun View.fadeIn() {
|
||||
apply {
|
||||
// Set the content view to 0% opacity but visible, so that it is visible
|
||||
// (but fully transparent) during the animation.
|
||||
alpha = 0f
|
||||
hide()
|
||||
|
||||
// Animate the content view to 100% opacity, and clear any animation
|
||||
// listener set on the view.
|
||||
animate()
|
||||
.alpha(1f)
|
||||
.setDuration(shortAnimationDuration.toLong())
|
||||
.setListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
show()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun View.fadeOut() {
|
||||
apply {
|
||||
// Set the content view to 0% opacity but visible, so that it is visible
|
||||
// (but fully transparent) during the animation.
|
||||
alpha = 1f
|
||||
show()
|
||||
|
||||
// Animate the content view to 100% opacity, and clear any animation
|
||||
// listener set on the view.
|
||||
animate()
|
||||
.alpha(0f)
|
||||
.setDuration(shortAnimationDuration.toLong())
|
||||
.setListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
hide()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@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,65 +0,0 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.navigation.NavController
|
||||
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.atlas_weather.R
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.settings.UnitSettingsActivity
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import kotlinx.android.synthetic.main.activity_main_navigation.*
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
lateinit var navHost: NavHostFragment
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main_navigation)
|
||||
|
||||
val navView: BottomNavigationView = findViewById(R.id.nav_view)
|
||||
setSupportActionBar(toolbar)
|
||||
|
||||
navHost = supportFragmentManager
|
||||
.findFragmentById(R.id.container) as NavHostFragment
|
||||
val navController = navHost.navController
|
||||
navController.setGraph(R.navigation.main_navigation)
|
||||
|
||||
setupBottomBar(navView, navController)
|
||||
}
|
||||
|
||||
private fun setupBottomBar(navView: BottomNavigationView, navController: NavController) {
|
||||
val tabs = setOf(R.id.nav_home, R.id.nav_world)
|
||||
val appBarConfiguration = AppBarConfiguration(tabs)
|
||||
|
||||
setupActionBarWithNavController(navController, appBarConfiguration)
|
||||
navView.setupWithNavController(navController)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
menuInflater.inflate(R.menu.menu_main, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
// Handle action bar item clicks here. The action bar will
|
||||
// automatically handle clicks on the Home/Up button, so long
|
||||
// as you specify a parent activity in AndroidManifest.xml.
|
||||
when (item.itemId) {
|
||||
R.id.action_settings -> {
|
||||
val i = Intent(this, UnitSettingsActivity::class.java)
|
||||
startActivity(i)
|
||||
return true
|
||||
}
|
||||
android.R.id.home -> onBackPressed()
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.settings
|
||||
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.ComponentName
|
||||
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.monoWeather.widget.NewAppWidget
|
||||
|
||||
|
||||
class UnitSettingsActivity : PreferenceActivity() {
|
||||
private var prefListener: OnSharedPreferenceChangeListener? = null
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
PreferenceManager.setDefaultValues(this, R.xml.prefs_screen, 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 == "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)
|
||||
}
|
||||
|
||||
|
||||
class MyPreferenceFragment : PreferenceFragment() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
addPreferencesFromResource(R.xml.prefs_screen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.widget
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.PendingIntent
|
||||
import android.app.PendingIntent.FLAG_IMMUTABLE
|
||||
import android.app.TaskStackBuilder
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.appwidget.AppWidgetProvider
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.widget.RemoteViews
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.core.app.JobIntentService
|
||||
import com.squareup.picasso.Picasso
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
abstract class BaseWidgetServiceIntentClass<T : AppWidgetProvider> : JobIntentService() {
|
||||
|
||||
lateinit var appWidgetManager: AppWidgetManager
|
||||
lateinit var appWidgetIds: IntArray
|
||||
|
||||
fun initBaseWidget(componentName: ComponentName) {
|
||||
appWidgetManager = AppWidgetManager.getInstance(baseContext)
|
||||
appWidgetIds = appWidgetManager.getAppWidgetIds(componentName)
|
||||
}
|
||||
|
||||
fun createRemoteView(@LayoutRes id: Int): RemoteViews {
|
||||
return RemoteViews(packageName, id)
|
||||
}
|
||||
|
||||
// Create pending intent commonly used for 'click to update' features
|
||||
fun createUpdatePendingIntent(
|
||||
appWidgetProvider: Class<T>,
|
||||
appWidgetId: Int
|
||||
): PendingIntent? {
|
||||
val seconds = (System.currentTimeMillis() / 1000L).toInt()
|
||||
val intentUpdate = Intent(applicationContext, appWidgetProvider)
|
||||
intentUpdate.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||
val idArray = intArrayOf(appWidgetId)
|
||||
intentUpdate.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, idArray)
|
||||
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
PendingIntent.getBroadcast(this, seconds, intentUpdate, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
|
||||
} else {
|
||||
PendingIntent.getBroadcast(this, seconds, intentUpdate, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* create a pending intent used to navigate to activity:
|
||||
* @param activityClass
|
||||
*/
|
||||
fun <T : Activity> createClickingPendingIntent(activityClass: Class<T>): PendingIntent {
|
||||
val clickIntentTemplate = Intent(this, activityClass)
|
||||
|
||||
return TaskStackBuilder.create(this)
|
||||
.addNextIntentWithParentStack(clickIntentTemplate)
|
||||
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE)
|
||||
}
|
||||
|
||||
fun setImageView(
|
||||
path: String?,
|
||||
views: RemoteViews,
|
||||
@IdRes viewId: Int,
|
||||
appWidgetId: Int
|
||||
) {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
Picasso.get().load(path).into(views, viewId, intArrayOf(appWidgetId))
|
||||
}
|
||||
}
|
||||
|
||||
open fun bindView(widgetId: Int, views: RemoteViews, data: Any?) {}
|
||||
open fun bindEmptyView(widgetId: Int, views: RemoteViews, data: Any?) {}
|
||||
open fun bindErrorView(widgetId: Int, views: RemoteViews, data: Any?) {}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.widget
|
||||
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.appwidget.AppWidgetProvider
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.widget.WidgetJobServiceIntent.Companion.enqueueWork
|
||||
|
||||
/**
|
||||
* Implementation of App Widget functionality.
|
||||
*/
|
||||
class NewAppWidget : AppWidgetProvider() {
|
||||
|
||||
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
|
||||
super.onUpdate(context, appWidgetManager, appWidgetIds)
|
||||
|
||||
loadWidget(context)
|
||||
}
|
||||
|
||||
override fun onEnabled(context: Context) {
|
||||
super.onEnabled(context)
|
||||
|
||||
loadWidget(context)
|
||||
}
|
||||
|
||||
override fun onDisabled(context: Context) { }
|
||||
|
||||
private fun loadWidget(context: Context){
|
||||
val mIntent = Intent(context, WidgetJobServiceIntent::class.java)
|
||||
enqueueWork(context, mIntent)
|
||||
}
|
||||
}
|
||||
@@ -1,220 +0,0 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.widget
|
||||
|
||||
import android.Manifest.permission.ACCESS_COARSE_LOCATION
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.PendingIntent
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||
import android.icu.text.SimpleDateFormat
|
||||
import android.os.PowerManager
|
||||
import android.widget.RemoteViews
|
||||
import android.os.Build
|
||||
import androidx.core.app.ActivityCompat.checkSelfPermission
|
||||
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.InnerWidgetCellData
|
||||
import com.appttude.h_mal.atlas_weather.model.widget.WidgetWeatherCollection
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.MainActivity
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.widget.WidgetState.*
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.widget.WidgetState.Companion.getWidgetState
|
||||
import com.appttude.h_mal.atlas_weather.utils.isInternetAvailable
|
||||
import com.appttude.h_mal.atlas_weather.utils.tryOrNullSuspended
|
||||
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
|
||||
import java.util.*
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of a JobIntentService used for home screen widget
|
||||
*/
|
||||
const val HALF_DAY = 43200000L
|
||||
class WidgetJobServiceIntent : BaseWidgetServiceIntentClass<NewAppWidget>() {
|
||||
|
||||
private val kodein = LateInitKodein()
|
||||
private val helper: ServicesHelper by kodein.instance()
|
||||
|
||||
override fun onHandleWork(intent: Intent) {
|
||||
// We have received work to do. The system or framework is already
|
||||
// holding a wake lock for us at this point, so we can just go.
|
||||
kodein.baseKodein = (applicationContext as KodeinAware).kodein
|
||||
executeWidgetUpdate()
|
||||
}
|
||||
|
||||
private fun executeWidgetUpdate() {
|
||||
val componentName = ComponentName(this, NewAppWidget::class.java)
|
||||
initBaseWidget(componentName)
|
||||
|
||||
initiateWidgetUpdate(getCurrentWidgetState())
|
||||
}
|
||||
|
||||
private fun initiateWidgetUpdate(state: WidgetState) {
|
||||
when (state) {
|
||||
NO_LOCATION, SCREEN_ON_CONNECTION_UNAVAILABLE -> updateErrorWidget(state)
|
||||
SCREEN_ON_CONNECTION_AVAILABLE -> updateWidget(false)
|
||||
SCREEN_OFF_CONNECTION_AVAILABLE -> updateWidget(true)
|
||||
SCREEN_OFF_CONNECTION_UNAVAILABLE -> return
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateWidget(fromStorage: Boolean) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val result = getWidgetWeather(fromStorage)
|
||||
appWidgetIds.forEach { id -> setupView(id, result) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateErrorWidget(state: WidgetState) {
|
||||
appWidgetIds.forEach { id -> setEmptyView(id, state) }
|
||||
}
|
||||
|
||||
private fun getCurrentWidgetState(): WidgetState {
|
||||
val pm = getSystemService(POWER_SERVICE) as PowerManager
|
||||
val isScreenOn = pm.isInteractive
|
||||
val locationGranted =
|
||||
checkSelfPermission(this, ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED
|
||||
val internetAvailable = isInternetAvailable(this.applicationContext)
|
||||
|
||||
return getWidgetState(locationGranted, isScreenOn, internetAvailable)
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
suspend fun getWidgetWeather(storageOnly: Boolean): WidgetWeatherCollection? {
|
||||
return tryOrNullSuspended {
|
||||
if (!storageOnly) helper.fetchData()
|
||||
helper.getWidgetWeatherCollection()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setEmptyView(appWidgetId: Int, state: WidgetState) {
|
||||
val error = when (state) {
|
||||
NO_LOCATION -> "No Location Permission"
|
||||
SCREEN_ON_CONNECTION_UNAVAILABLE -> "No network available"
|
||||
else -> "No data"
|
||||
}
|
||||
|
||||
val views = createRemoteView(R.layout.weather_app_widget)
|
||||
bindErrorView(appWidgetId, views, error)
|
||||
}
|
||||
|
||||
private fun setupView(
|
||||
appWidgetId: Int,
|
||||
collection: WidgetWeatherCollection?
|
||||
) {
|
||||
val views = createRemoteView(R.layout.weather_app_widget)
|
||||
setLastUpdated(views, collection?.widgetData?.timeStamp)
|
||||
views.setInt(R.id.whole_widget_view, "setBackgroundColor", helper.getWidgetBackground())
|
||||
|
||||
if (collection != null) {
|
||||
bindView(appWidgetId, views, collection)
|
||||
} else {
|
||||
bindEmptyView(appWidgetId, views, "No weather available")
|
||||
}
|
||||
}
|
||||
|
||||
override fun bindErrorView(
|
||||
widgetId: Int,
|
||||
views: RemoteViews,
|
||||
data: Any?
|
||||
) {
|
||||
bindEmptyView(widgetId, views, data)
|
||||
}
|
||||
|
||||
override fun bindEmptyView(
|
||||
widgetId: Int,
|
||||
views: RemoteViews,
|
||||
data: Any?
|
||||
) {
|
||||
val clickUpdate = createUpdatePendingIntent(NewAppWidget::class.java, widgetId)
|
||||
|
||||
views.apply {
|
||||
setTextViewText(R.id.widget_current_location, data as String)
|
||||
setImageViewResource(R.id.widget_current_icon, R.drawable.ic_baseline_cloud_off_24)
|
||||
setImageViewResource(R.id.location_icon, 0)
|
||||
|
||||
setTextViewText(R.id.widget_main_temp, "")
|
||||
setTextViewText(R.id.widget_feel_temp, "")
|
||||
|
||||
setOnClickPendingIntent(R.id.widget_current_icon, clickUpdate)
|
||||
setOnClickPendingIntent(R.id.widget_current_location, clickUpdate)
|
||||
appWidgetManager.updateAppWidget(widgetId, this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun bindView(widgetId: Int, views: RemoteViews, data: Any?) {
|
||||
val clickUpdate = createUpdatePendingIntent(NewAppWidget::class.java, widgetId)
|
||||
val clickToMain = createClickingPendingIntent(MainActivity::class.java)
|
||||
|
||||
val collection = data as WidgetWeatherCollection
|
||||
val weather = collection.widgetData
|
||||
views.apply {
|
||||
setTextViewText(R.id.widget_main_temp, weather.currentTemp)
|
||||
setTextViewText(R.id.widget_feel_temp, "°C")
|
||||
setTextViewText(R.id.widget_current_location, weather.location)
|
||||
setImageViewResource(R.id.location_icon, R.drawable.location_flag)
|
||||
setImageView(weather.icon, this, R.id.widget_current_icon, widgetId)
|
||||
setOnClickPendingIntent(R.id.widget_current_icon, clickUpdate)
|
||||
setOnClickPendingIntent(R.id.widget_current_location, clickUpdate)
|
||||
|
||||
loadCells(widgetId, this, collection.forecast, clickToMain)
|
||||
// Instruct the widget manager to update the widget
|
||||
appWidgetManager.updateAppWidget(widgetId, views)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadCells(
|
||||
appWidgetId: Int,
|
||||
remoteViews: RemoteViews,
|
||||
weather: List<InnerWidgetCellData>,
|
||||
clickIntent: PendingIntent
|
||||
) {
|
||||
(0..4).forEach { i ->
|
||||
val containerId: Int = resources.getIdentifier("widget_item_$i", "id", packageName)
|
||||
val dayId: Int = resources.getIdentifier("widget_item_day_$i", "id", packageName)
|
||||
val imageId: Int = resources.getIdentifier("widget_item_image_$i", "id", packageName)
|
||||
val tempId: Int = resources.getIdentifier("widget_item_temp_high_$i", "id", packageName)
|
||||
|
||||
val it = weather[i]
|
||||
|
||||
remoteViews.setTextViewText(dayId, it.date)
|
||||
remoteViews.setTextViewText(tempId, it.highTemp)
|
||||
setImageView(it.icon, remoteViews, imageId, appWidgetId)
|
||||
remoteViews.setOnClickPendingIntent(containerId, clickIntent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setLastUpdated(views: RemoteViews, timeStamp: Long?) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && timeStamp != null) {
|
||||
val difference = System.currentTimeMillis().minus(timeStamp)
|
||||
|
||||
val status = if (difference > HALF_DAY) {
|
||||
"12hrs ago"
|
||||
} else {
|
||||
val date = Date(timeStamp)
|
||||
val sdf = SimpleDateFormat("HH:mm", Locale.getDefault())
|
||||
sdf.format(date)
|
||||
}
|
||||
|
||||
views.setTextViewText(R.id.widget_current_status, "last updated: $status")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Unique job ID for this service.
|
||||
*/
|
||||
private const val JOB_ID = 1000
|
||||
|
||||
/**
|
||||
* Convenience method for enqueuing work in to this service.
|
||||
*/
|
||||
fun enqueueWork(context: Context, work: Intent) {
|
||||
enqueueWork(context, WidgetJobServiceIntent::class.java, JOB_ID, work)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.widget
|
||||
|
||||
enum class WidgetState {
|
||||
NO_LOCATION,
|
||||
SCREEN_ON_CONNECTION_AVAILABLE,
|
||||
SCREEN_ON_CONNECTION_UNAVAILABLE,
|
||||
SCREEN_OFF_CONNECTION_AVAILABLE,
|
||||
SCREEN_OFF_CONNECTION_UNAVAILABLE;
|
||||
|
||||
companion object {
|
||||
fun getWidgetState(
|
||||
locationAvailable: Boolean,
|
||||
screenOn: Boolean,
|
||||
connectionAvailable: Boolean
|
||||
): WidgetState {
|
||||
return if (!locationAvailable)
|
||||
NO_LOCATION
|
||||
else if (screenOn && connectionAvailable)
|
||||
SCREEN_ON_CONNECTION_AVAILABLE
|
||||
else if (screenOn && !connectionAvailable)
|
||||
SCREEN_ON_CONNECTION_UNAVAILABLE
|
||||
else if (!screenOn && connectionAvailable)
|
||||
SCREEN_OFF_CONNECTION_AVAILABLE
|
||||
else
|
||||
SCREEN_OFF_CONNECTION_UNAVAILABLE
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.dialog
|
||||
package com.appttude.h_mal.monoWeather.dialog
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
@@ -14,7 +14,6 @@ interface DeclarationBuilder{
|
||||
|
||||
fun Context.readFromResources(@StringRes id: Int) = resources.getString(id)
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.N)
|
||||
fun buildMessage(): CharSequence? {
|
||||
val link1 = "<font color='blue'><a href=\"$link\">here</a></font>"
|
||||
val message = "$message See my privacy policy: $link1"
|
||||
@@ -1,13 +1,10 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.dialog
|
||||
package com.appttude.h_mal.monoWeather.dialog
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.appttude.h_mal.atlas_weather.R
|
||||
|
||||
|
||||
class PermissionsDeclarationDialog(context: Context) : BaseDeclarationDialog(context) {
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui
|
||||
package com.appttude.h_mal.monoWeather.ui
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
@@ -1,14 +1,12 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui
|
||||
package com.appttude.h_mal.monoWeather.ui
|
||||
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.appttude.h_mal.atlas_weather.R
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.WeatherRecyclerAdapter
|
||||
import com.appttude.h_mal.monoWeather.ui.home.adapter.WeatherRecyclerAdapter
|
||||
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
||||
import kotlinx.android.synthetic.main.fragment_home.*
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.details
|
||||
package com.appttude.h_mal.monoWeather.ui.details
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
@@ -1,22 +1,21 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.home
|
||||
package com.appttude.h_mal.monoWeather.ui.home
|
||||
|
||||
import android.Manifest
|
||||
import android.Manifest.permission.ACCESS_COARSE_LOCATION
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.observe
|
||||
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.model.forecast.Forecast
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.dialog.PermissionsDeclarationDialog
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.BaseFragment
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.WeatherRecyclerAdapter
|
||||
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
||||
import com.appttude.h_mal.monoWeather.dialog.PermissionsDeclarationDialog
|
||||
import com.appttude.h_mal.monoWeather.ui.BaseFragment
|
||||
import com.appttude.h_mal.monoWeather.ui.home.adapter.WeatherRecyclerAdapter
|
||||
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.*
|
||||
@@ -35,6 +34,7 @@ class HomeFragment : BaseFragment(R.layout.fragment_home) {
|
||||
@SuppressLint("MissingPermission")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
|
||||
val recyclerAdapter = WeatherRecyclerAdapter(itemClick = {
|
||||
navigateToFurtherDetails(it)
|
||||
@@ -86,4 +86,14 @@ class HomeFragment : BaseFragment(R.layout.fragment_home) {
|
||||
.actionHomeFragmentToFurtherDetailsFragment(forecast)
|
||||
navigateTo(directions)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
inflater.inflate(R.menu.menu_main, menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
val navController = findNavController(requireActivity(), R.id.container)
|
||||
return item.onNavDestinationSelected(navController) || super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter
|
||||
package com.appttude.h_mal.monoWeather.ui.home.adapter
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
@@ -1,14 +1,14 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter
|
||||
package com.appttude.h_mal.monoWeather.ui.home.adapter
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.appttude.h_mal.atlas_weather.R
|
||||
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.monoWeather.ui.EmptyViewHolder
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.forecast.ViewHolderForecast
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.forecastDaily.ViewHolderForecastDaily
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.further.ViewHolderFurtherDetails
|
||||
import com.appttude.h_mal.monoWeather.ui.EmptyViewHolder
|
||||
import com.appttude.h_mal.monoWeather.ui.home.adapter.forecast.ViewHolderForecast
|
||||
import com.appttude.h_mal.monoWeather.ui.home.adapter.forecastDaily.ViewHolderForecastDaily
|
||||
import com.appttude.h_mal.monoWeather.ui.home.adapter.further.ViewHolderFurtherDetails
|
||||
import com.appttude.h_mal.atlas_weather.utils.generateView
|
||||
|
||||
class WeatherRecyclerAdapter(
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.forecast
|
||||
package com.appttude.h_mal.monoWeather.ui.home.adapter.forecast
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.forecast
|
||||
package com.appttude.h_mal.monoWeather.ui.home.adapter.forecast
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.forecast
|
||||
package com.appttude.h_mal.monoWeather.ui.home.adapter.forecast
|
||||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.forecastDaily
|
||||
package com.appttude.h_mal.monoWeather.ui.home.adapter.forecastDaily
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.further
|
||||
package com.appttude.h_mal.monoWeather.ui.home.adapter.further
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.home.adapter.further
|
||||
package com.appttude.h_mal.monoWeather.ui.home.adapter.further
|
||||
|
||||
import android.view.View
|
||||
import android.widget.GridView
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.appttude.h_mal.monoWeather.ui.settings
|
||||
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.ComponentName
|
||||
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.widget.NewAppWidget
|
||||
|
||||
class SettingsFragment : PreferenceFragmentCompat() {
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.prefs_screen, 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 == "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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.widget
|
||||
package com.appttude.h_mal.monoWeather.ui.widget
|
||||
|
||||
import android.Manifest.permission.ACCESS_COARSE_LOCATION
|
||||
import android.app.Activity
|
||||
@@ -11,7 +11,7 @@ import android.widget.TextView
|
||||
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.monoWeather.dialog.DeclarationBuilder
|
||||
import com.appttude.h_mal.monoWeather.dialog.DeclarationBuilder
|
||||
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
||||
import kotlinx.android.synthetic.monoWeather.permissions_declaration_dialog.*
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.world
|
||||
package com.appttude.h_mal.monoWeather.ui.world
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.observe
|
||||
import com.appttude.h_mal.atlas_weather.R
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.BaseFragment
|
||||
import com.appttude.h_mal.monoWeather.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.utils.hideKeyboard
|
||||
@@ -1,15 +1,13 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.world
|
||||
package com.appttude.h_mal.monoWeather.ui.world
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.observe
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.appttude.h_mal.atlas_weather.R
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.BaseFragment
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.world.WorldFragmentDirections.actionWorldFragmentToWorldItemFragment
|
||||
import com.appttude.h_mal.monoWeather.ui.BaseFragment
|
||||
import com.appttude.h_mal.monoWeather.ui.world.WorldFragmentDirections.actionWorldFragmentToWorldItemFragment
|
||||
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.ui.world
|
||||
package com.appttude.h_mal.monoWeather.ui.world
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@@ -7,7 +7,7 @@ import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.monoWeather.ui.EmptyViewHolder
|
||||
import com.appttude.h_mal.monoWeather.ui.EmptyViewHolder
|
||||
import com.appttude.h_mal.atlas_weather.utils.generateView
|
||||
import com.appttude.h_mal.atlas_weather.utils.loadImage
|
||||
|
||||
@@ -93,13 +93,9 @@ class WorldRecyclerAdapter(
|
||||
avgTempTV.text = data?.forecast?.get(0)?.mainTemp
|
||||
tempUnit.text = itemView.context.getString(R.string.degrees)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class BaseViewHolder<T : Any>(cellView: View) : RecyclerView.ViewHolder(cellView) {
|
||||
|
||||
abstract fun bindData(data : T?)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user