Compare commits

...

8 Commits

230 changed files with 1544 additions and 859 deletions

3
.gitignore vendored
View File

@ -8,4 +8,5 @@
/captures /captures
.externalNativeBuild .externalNativeBuild
/tasksintegration/build /tasksintegration/build
apikey.properties apikey.properties
/app/google-services.json

Binary file not shown.

2
.idea/gradle.xml generated
View File

@ -11,8 +11,6 @@
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" /> <option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/googlefit" />
<option value="$PROJECT_DIR$/tasksintegration" />
</set> </set>
</option> </option>
<option name="resolveModulePerSourceSet" value="false" /> <option name="resolveModulePerSourceSet" value="false" />

2
.idea/modules.xml generated
View File

@ -4,8 +4,6 @@
<modules> <modules>
<module fileurl="file://$PROJECT_DIR$/Another Widget.iml" filepath="$PROJECT_DIR$/Another Widget.iml" group="Another Widget" /> <module fileurl="file://$PROJECT_DIR$/Another Widget.iml" filepath="$PROJECT_DIR$/Another Widget.iml" group="Another Widget" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" group="Another Widget/app" /> <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" group="Another Widget/app" />
<module fileurl="file://$PROJECT_DIR$/googlefit/googlefit.iml" filepath="$PROJECT_DIR$/googlefit/googlefit.iml" group="Another Widget/googlefit" />
<module fileurl="file://$PROJECT_DIR$/tasksintegration/tasksintegration.iml" filepath="$PROJECT_DIR$/tasksintegration/tasksintegration.iml" group="Another Widget/tasksintegration" />
</modules> </modules>
</component> </component>
</project> </project>

View File

@ -10,6 +10,10 @@ apply plugin: 'kotlin-android-extensions'
apply plugin: 'realm-android' apply plugin: 'realm-android'
def apiKeyPropertiesFile = rootProject.file("apikey.properties")
def apiKeyProperties = new Properties()
apiKeyProperties.load(new FileInputStream(apiKeyPropertiesFile))
android { android {
compileSdkVersion 29 compileSdkVersion 29
buildToolsVersion "29.0.3" buildToolsVersion "29.0.3"
@ -18,10 +22,12 @@ android {
applicationId "com.tommasoberlose.anotherwidget" applicationId "com.tommasoberlose.anotherwidget"
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 29 targetSdkVersion 29
versionCode 81 versionCode 87
versionName "2.0.6" versionName "2.0.8"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
manifestPlaceholders = [ "AWARENESS_API_KEY": apiKeyProperties['AWARENESS_API_KEY']]
} }
buildTypes { buildTypes {
@ -52,10 +58,6 @@ android {
} }
viewBinding.enabled = true viewBinding.enabled = true
dynamicFeatures = [":tasksintegration", ":googlefit"]
} }
dependencies { dependencies {
@ -98,6 +100,10 @@ dependencies {
implementation 'com.github.bumptech.glide:glide:4.11.0' implementation 'com.github.bumptech.glide:glide:4.11.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0' kapt 'com.github.bumptech.glide:compiler:4.11.0'
// Fitness
implementation 'com.google.android.gms:play-services-fitness:18.0.0'
implementation 'com.google.android.gms:play-services-auth:18.0.0'
//Weather //Weather
implementation 'com.github.KwabenBerko:OpenWeatherMap-Android-Library:2.0.2' implementation 'com.github.KwabenBerko:OpenWeatherMap-Android-Library:2.0.2'
implementation 'com.google.android.gms:play-services-location:17.0.0' implementation 'com.google.android.gms:play-services-location:17.0.0'

View File

@ -1,40 +0,0 @@
{
"project_info": {
"project_number": "791844924473",
"firebase_url": "https://anotherwidget-182008.firebaseio.com",
"project_id": "anotherwidget-182008",
"storage_bucket": "anotherwidget-182008.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:791844924473:android:0ad4f6e3890f1ad320b1e8",
"android_client_info": {
"package_name": "com.tommasoberlose.anotherwidget"
}
},
"oauth_client": [
{
"client_id": "791844924473-73dh46rorjq8vm97dgbn6can2dcpqlf0.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAeJRXstqnzebibxmm3FRM98nbwE_kC8tA"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "791844924473-73dh46rorjq8vm97dgbn6can2dcpqlf0.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}

Binary file not shown.

View File

@ -10,6 +10,10 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="com.android.vending.BILLING" /> <uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.gms.permission.ACTIVITY_RECOGNITION"/>
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
<application <application
android:allowBackup="true" android:allowBackup="true"
@ -82,44 +86,16 @@
android:enabled="true" android:enabled="true"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_WEATHER_UPDATE" /> <action android:name="com.tommasoberlose.anotherwidget.action.ACTION_WEATHER_UPDATE" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" /> <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.TIME_SET" /> <action android:name="android.intent.action.TIME_SET" />
<action android:name="android.intent.action.TIMEZONE_CHANGED" /> <action android:name="android.intent.action.TIMEZONE_CHANGED" />
<action android:name="android.intent.action.LOCALE_CHANGED" /> <action android:name="android.intent.action.LOCALE_CHANGED" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver
android:name=".receivers.PlayerReceiver"
android:enabled="true"
android:exported="true"
tools:ignore="ExportedReceiver">
<intent-filter>
<action android:name="com.android.music.metachanged" />
<action android:name="com.android.music.playstatechanged" />
<action android:name="com.android.music.playbackcomplete" />
<action android:name="com.android.music.queuechanged" />
<action android:name="com.htc.music.metachanged" />
<action android:name="fm.last.android.metachanged" />
<action android:name="com.sec.android.app.music.metachanged" />
<action android:name="com.nullsoft.winamp.metachanged" />
<action android:name="com.amazon.mp3.metachanged" />
<action android:name="com.miui.player.metachanged" />
<action android:name="com.real.IMP.metachanged" />
<action android:name="com.sonyericsson.music.metachanged" />
<action android:name="com.rdio.android.metachanged" />
<action android:name="com.samsung.sec.android.MusicPlayer.metachanged" />
<action android:name="com.andrew.apollo.metachanged" />
<action android:name="com.spotify.music.playbackstatechanged"/>
<action android:name="com.spotify.music.metadatachanged"/>
<action android:name="com.spotify.music.queuechanged"/>
</intent-filter>
</receiver>
<receiver <receiver
android:name=".receivers.WidgetClickListenerReceiver" android:name=".receivers.WidgetClickListenerReceiver"
android:enabled="true" android:enabled="true"
@ -146,6 +122,31 @@
<action android:name="android.service.notification.NotificationListenerService" /> <action android:name="android.service.notification.NotificationListenerService" />
</intent-filter> </intent-filter>
</service> </service>
<receiver android:name=".receivers.BatteryLevelReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
<action android:name="android.intent.action.BATTERY_LOW"/>
<action android:name="android.intent.action.BATTERY_OKAY"/>
</intent-filter>
</receiver>
<receiver android:name=".receivers.ActivityDetectionReceiver"
android:exported="false"
android:permission="com.google.android.gms.permission.ACTIVITY_RECOGNITION">
<intent-filter>
<action android:name="com.mypackage.ACTION_PROCESS_ACTIVITY_TRANSITIONS" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<meta-data
android:name="com.google.android.awareness.API_KEY"
android:value="${AWARENESS_API_KEY}"/>
</application> </application>
</manifest> </manifest>

View File

@ -1,6 +1,7 @@
package com.tommasoberlose.anotherwidget package com.tommasoberlose.anotherwidget
import android.app.Application import android.app.Application
import android.util.Log
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import com.chibatching.kotpref.Kotpref import com.chibatching.kotpref.Kotpref
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics

View File

@ -0,0 +1,27 @@
package com.tommasoberlose.anotherwidget.components
import android.content.Context
import android.view.View
import androidx.appcompat.app.AlertDialog
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.global.Preferences
import kotlinx.android.synthetic.main.custom_notes_dialog_layout.view.*
class CustomNotesDialog(context: Context) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
init {
val view = View.inflate(context, R.layout.custom_notes_dialog_layout, null)
view.notes.setText(Preferences.customNotes)
view.action_positive.setOnClickListener {
Preferences.customNotes = view.notes.text.toString()
this.dismiss()
}
view.notes.requestFocus()
setContentView(view)
}
}

View File

@ -0,0 +1,99 @@
package com.tommasoberlose.anotherwidget.components
import android.content.Context
import android.content.res.ColorStateList
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.card.MaterialCardView
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
import com.tommasoberlose.anotherwidget.helpers.GlanceProviderHelper
import com.tommasoberlose.anotherwidget.models.GlanceProvider
import kotlinx.android.synthetic.main.glance_provider_sort_bottom_menu.view.*
import kotlinx.coroutines.*
import net.idik.lib.slimadapter.SlimAdapter
import java.util.*
import kotlin.collections.ArrayList
class GlanceProviderSortMenu(
context: Context
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
private lateinit var adapter: SlimAdapter
override fun show() {
val view = View.inflate(context, R.layout.glance_provider_sort_bottom_menu, null)
// Header
view.header_text.text = context.getString(R.string.settings_sort_glance_providers_title)
// List
adapter = SlimAdapter.create()
view.menu.setHasFixedSize(true)
val mLayoutManager = LinearLayoutManager(context)
view.menu.layoutManager = mLayoutManager
adapter = SlimAdapter.create()
adapter
.register<GlanceProvider>(R.layout.glance_provider_item) { item, injector ->
injector
.text(R.id.title, item.title)
.with<ImageView>(R.id.icon) {
it.setImageDrawable(ContextCompat.getDrawable(context, item.icon))
}
}
.attachTo(view.menu)
val mIth = ItemTouchHelper(
object : ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP or ItemTouchHelper.DOWN,
ItemTouchHelper.LEFT
) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder
): Boolean {
val fromPos = viewHolder.adapterPosition
val toPos = target.adapterPosition
// move item in `fromPos` to `toPos` in adapter.
adapter.notifyItemMoved(fromPos, toPos)
val list = GlanceProviderHelper.getGlanceProviders()
Collections.swap(list, fromPos, toPos)
GlanceProviderHelper.saveGlanceProviderOrder(list)
return true
}
override fun onSwiped(
viewHolder: RecyclerView.ViewHolder,
direction: Int
) {
// remove from adapter
}
})
mIth.attachToRecyclerView(view.menu)
adapter.updateData(
GlanceProviderHelper.getGlanceProviders()
.filter { it != Constants.GlanceProviderId.BATTERY_LEVEL_LOW }
.mapNotNull { GlanceProviderHelper.getGlanceProviderById(context, it) }
)
setContentView(view)
super.show()
}
}

View File

@ -39,7 +39,7 @@ class EventRepository(val context: Context) {
} }
fun saveNextEventData(event: Event) { fun saveNextEventData(event: Event) {
Preferences.nextEventId = event.id Preferences.nextEventId = event.eventID
} }
fun getNextEvent(): Event? { fun getNextEvent(): Event? {
@ -64,11 +64,11 @@ class EventRepository(val context: Context) {
fun goToNextEvent() { fun goToNextEvent() {
val eventList = getEvents() val eventList = getEvents()
if (eventList.isNotEmpty()) { if (eventList.isNotEmpty()) {
val index = eventList.indexOfFirst { it.id == Preferences.nextEventId } val index = eventList.indexOfFirst { it.eventID == Preferences.nextEventId }
if (index > -1 && index < eventList.size - 1) { if (index > -1 && index < eventList.size - 1) {
Preferences.nextEventId = eventList[index + 1]!!.id Preferences.nextEventId = eventList[index + 1]!!.eventID
} else { } else {
Preferences.nextEventId = eventList.first()!!.id Preferences.nextEventId = eventList.first()!!.eventID
} }
} else { } else {
resetNextEventData() resetNextEventData()
@ -80,11 +80,11 @@ class EventRepository(val context: Context) {
fun goToPreviousEvent() { fun goToPreviousEvent() {
val eventList = getEvents() val eventList = getEvents()
if (eventList.isNotEmpty()) { if (eventList.isNotEmpty()) {
val index = eventList.indexOfFirst { it.id == Preferences.nextEventId } val index = eventList.indexOfFirst { it.eventID == Preferences.nextEventId }
if (index > 0) { if (index > 0) {
Preferences.nextEventId = eventList[index - 1]!!.id Preferences.nextEventId = eventList[index - 1]!!.eventID
} else { } else {
Preferences.nextEventId = eventList.last()!!.id Preferences.nextEventId = eventList.last()!!.eventID
} }
} else { } else {
resetNextEventData() resetNextEventData()
@ -95,11 +95,7 @@ class EventRepository(val context: Context) {
fun getEvents(): RealmResults<Event> { fun getEvents(): RealmResults<Event> {
val now = Calendar.getInstance().timeInMillis val now = Calendar.getInstance().timeInMillis
val list = realm.where(Event::class.java).greaterThan("endDate", now).findAll() return realm.where(Event::class.java).greaterThan("endDate", now).findAll()
realm.executeTransactionAsync {
it.where(Event::class.java).lessThanOrEqualTo("endDate", now).findAll().deleteAllFromRealm()
}
return list
} }
fun getEventsCount(): Int = getEvents().size fun getEventsCount(): Int = getEvents().size

View File

@ -18,8 +18,8 @@ object Constants {
enum class GlanceProviderId(val id: String) { enum class GlanceProviderId(val id: String) {
PLAYING_SONG("PLAYING_SONG"), PLAYING_SONG("PLAYING_SONG"),
NEXT_CLOCK_ALARM("NEXT_CLOCK_ALARM"), NEXT_CLOCK_ALARM("NEXT_CLOCK_ALARM"),
// BATTERY_LEVEL_LOW("BATTERY_LEVEL_LOW"), BATTERY_LEVEL_LOW("BATTERY_LEVEL_LOW"),
// CUSTOM_INFO("CUSTOM_INFO"), CUSTOM_INFO("CUSTOM_INFO"),
// GOOGLE_FIT_STEPS("GOOGLE_FIT_STEPS") GOOGLE_FIT_STEPS("GOOGLE_FIT_STEPS")
} }
} }

View File

@ -48,6 +48,7 @@ object Preferences : KotprefModel() {
var clockTextColor by stringPref(default = "#FFFFFF") var clockTextColor by stringPref(default = "#FFFFFF")
var clockTextAlpha by stringPref(default = "FF") var clockTextAlpha by stringPref(default = "FF")
var showAMPMIndicator by booleanPref(default = true)
// Global // Global
var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 26f) var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 26f)
@ -77,10 +78,12 @@ object Preferences : KotprefModel() {
// Glance // Glance
var showGlance by booleanPref(default = true) var showGlance by booleanPref(default = true)
var enabledGlanceProviderOrder by stringPref(default = "") var enabledGlanceProviderOrder by stringPref(default = "")
var customInfo by stringPref(default = "") var customNotes by stringPref(default = "")
var showNextAlarm by booleanPref(default = false) var showNextAlarm by booleanPref(default = true)
var showBatteryCharging by booleanPref(default = false)
var isBatteryLevelLow by booleanPref(default = false) var isBatteryLevelLow by booleanPref(default = false)
var googleFitSteps by longPref(default = -1) var googleFitSteps by longPref(default = -1)
var showDailySteps by booleanPref(default = false)
var showMusic by booleanPref(default = false) var showMusic by booleanPref(default = false)
var mediaInfoFormat by stringPref(default = "") var mediaInfoFormat by stringPref(default = "")

View File

@ -2,6 +2,7 @@ package com.tommasoberlose.anotherwidget.helpers
import android.content.Context import android.content.Context
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Constants import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.models.GlanceProvider import com.tommasoberlose.anotherwidget.models.GlanceProvider
@ -37,40 +38,47 @@ object GlanceProviderHelper {
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> { Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
GlanceProvider(providerId.id, GlanceProvider(providerId.id,
context.getString(R.string.settings_show_next_alarm_title), context.getString(R.string.settings_show_next_alarm_title),
R.drawable.round_alarm, R.drawable.round_alarm
context.getString(R.string.settings_show_next_alarm_subtitle)
) )
} }
Constants.GlanceProviderId.PLAYING_SONG -> { Constants.GlanceProviderId.PLAYING_SONG -> {
GlanceProvider(providerId.id, GlanceProvider(providerId.id,
context.getString(R.string.settings_show_music_title), context.getString(R.string.settings_show_music_title),
R.drawable.round_music_note, R.drawable.round_music_note
context.getString(R.string.settings_show_music_enabled_subtitle) )
}
Constants.GlanceProviderId.CUSTOM_INFO -> {
GlanceProvider(providerId.id,
context.getString(R.string.settings_custom_notes_title),
R.drawable.round_notes
)
}
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
GlanceProvider(providerId.id,
context.getString(R.string.settings_low_battery_level_title),
R.drawable.round_battery_charging_full
)
}
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
GlanceProvider(providerId.id,
context.getString(R.string.settings_daily_steps_title),
R.drawable.round_directions_walk
) )
} }
// Constants.GlanceProviderId.CUSTOM_INFO -> {
// GlanceProvider(providerId.id,
// context.getString(R.string.settings_show_next_alarm_title),
// R.drawable.round_event_note
// )
// }
// Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
// GlanceProvider(providerId.id,
// context.getString(R.string.settings_show_next_alarm_title),
// R.drawable.round_battery_charging_full
// )
// }
// Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
// GlanceProvider(providerId.id,
// context.getString(R.string.settings_show_next_alarm_title),
// R.drawable.round_directions_walk
// )
// }
else -> null
} }
} }
fun saveGlanceProviderOrder(list: ArrayList<Constants.GlanceProviderId>) { fun saveGlanceProviderOrder(list: ArrayList<Constants.GlanceProviderId>) {
Preferences.enabledGlanceProviderOrder = list.joinToString(separator = ",") Preferences.enabledGlanceProviderOrder = list.joinToString(separator = ",")
} }
fun showGlanceProviders(context: Context): Boolean {
return Preferences.showGlance && EventRepository(context).getEventsCount() == 0 && (
(Preferences.showNextAlarm && AlarmHelper.getNextAlarm(context) != "") ||
(MediaPlayerHelper.isSomeonePlaying(context)) ||
(Preferences.isBatteryLevelLow) ||
(Preferences.customNotes.isNotEmpty()) ||
(Preferences.showDailySteps && Preferences.googleFitSteps > 0)
)
}
} }

View File

@ -53,11 +53,4 @@ object WidgetHelper {
width to second * factor width to second * factor
} }
} }
fun showSpecialWeather(context: Context): Boolean {
return EventRepository(context).getEventsCount() == 0 && (
(Preferences.showNextAlarm && AlarmHelper.getNextAlarm(context) != "") ||
(MediaPlayerHelper.isSomeonePlaying(context))
)
}
} }

View File

@ -3,10 +3,5 @@ package com.tommasoberlose.anotherwidget.models
class GlanceProvider( class GlanceProvider(
val id: String, val id: String,
val title: String, val title: String,
val icon: Int, val icon: Int
val label: String = "",
val enabled: Boolean = false,
val isPermissionRequired: Boolean = false,
val isPermissionGranted: (() -> Boolean)? = null,
val requestPermission: (() -> Unit)? = null
) )

View File

@ -0,0 +1,177 @@
package com.tommasoberlose.anotherwidget.receivers
import android.Manifest
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Build
import android.util.Log
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.fitness.Fitness
import com.google.android.gms.fitness.FitnessOptions
import com.google.android.gms.fitness.data.DataType
import com.google.android.gms.fitness.data.Field.FIELD_STEPS
import com.google.android.gms.fitness.request.DataReadRequest
import com.google.android.gms.location.*
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import java.util.*
import java.util.concurrent.TimeUnit
class ActivityDetectionReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (ActivityTransitionResult.hasResult(intent)) {
val result = ActivityTransitionResult.extractResult(intent)!!
val lastEvent = result.transitionEvents.last()
if (lastEvent.activityType == DetectedActivity.WALKING || lastEvent.activityType == DetectedActivity.RUNNING && lastEvent.transitionType == ActivityTransition.ACTIVITY_TRANSITION_EXIT) {
requestDailySteps(context)
setTimeout(context)
} else {
resetDailySteps()
}
} else {
if (intent.action == Intent.ACTION_BOOT_COMPLETED || intent.action == Intent.ACTION_MY_PACKAGE_REPLACED && Preferences.showDailySteps && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION)) {
registerFence(context)
} else {
resetDailySteps()
}
}
}
private fun resetDailySteps() {
Preferences.googleFitSteps = -1
}
companion object {
val FITNESS_OPTIONS: FitnessOptions = FitnessOptions.builder()
.addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
.addDataType(DataType.AGGREGATE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
.build()
fun registerFence(context: Context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(
Manifest.permission.ACTIVITY_RECOGNITION)) {
val transitions = mutableListOf<ActivityTransition>()
transitions +=
ActivityTransition.Builder()
.setActivityType(DetectedActivity.WALKING)
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
.build()
transitions +=
ActivityTransition.Builder()
.setActivityType(DetectedActivity.RUNNING)
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
.build()
val request = ActivityTransitionRequest(transitions)
// myPendingIntent is the instance of PendingIntent where the app receives callbacks.
val task = ActivityRecognition.getClient(context)
.requestActivityTransitionUpdates(
request,
PendingIntent.getBroadcast(
context,
2,
Intent(context, ActivityDetectionReceiver::class.java),
0
)
)
task.addOnFailureListener { e: Exception ->
e.printStackTrace()
Preferences.showDailySteps = false
}
}
}
fun unregisterFence(context: Context) {
val task = ActivityRecognition.getClient(context)
.removeActivityTransitionUpdates(
PendingIntent.getBroadcast(
context,
2,
Intent(context, ActivityDetectionReceiver::class.java),
0
)
)
task.addOnCompleteListener {
if (it.isSuccessful) {
PendingIntent.getBroadcast(
context,
2,
Intent(context, ActivityDetectionReceiver::class.java),
0
).cancel()
}
}
}
fun requestDailySteps(context: Context) {
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(context)
if (account != null && GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS)) {
val cal: Calendar = Calendar.getInstance()
cal.set(Calendar.HOUR_OF_DAY, 0)
cal.set(Calendar.MINUTE, 0)
cal.set(Calendar.SECOND, 0)
cal.set(Calendar.MILLISECOND, 0)
val startTime: Long = cal.timeInMillis
cal.add(Calendar.DAY_OF_YEAR, 1)
val endTime: Long = cal.timeInMillis
val readRequest = DataReadRequest.Builder()
.aggregate(
DataType.TYPE_STEP_COUNT_DELTA,
DataType.AGGREGATE_STEP_COUNT_DELTA
)
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
.bucketByTime(1, TimeUnit.DAYS)
.build()
Fitness.getHistoryClient(context, account)
.readData(readRequest)
.addOnSuccessListener { response ->
Preferences.googleFitSteps = response.buckets.sumBy {
try {
it.getDataSet(DataType.AGGREGATE_STEP_COUNT_DELTA)?.dataPoints?.get(
0
)?.getValue(FIELD_STEPS)?.asInt() ?: 0
} catch (ex: Exception) {
0
}
}.toLong()
MainWidget.updateWidget(context)
}
}
}
fun setTimeout(context: Context) {
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
cancel(PendingIntent.getBroadcast(context, 0, Intent(context, ActivityDetectionReceiver::class.java), 0))
setExactAndAllowWhileIdle(
AlarmManager.RTC,
Calendar.getInstance().timeInMillis + 15 * 60 * 1000,
PendingIntent.getBroadcast(
context,
0,
Intent(context, ActivityDetectionReceiver::class.java),
0
)
)
}
}
}
}

View File

@ -0,0 +1,19 @@
package com.tommasoberlose.anotherwidget.receivers
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.BatteryManager
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
class BatteryLevelReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when(intent.action) {
Intent.ACTION_BATTERY_LOW -> Preferences.isBatteryLevelLow = true
Intent.ACTION_BATTERY_OKAY -> Preferences.isBatteryLevelLow = false
}
MainWidget.updateWidget(context)
}
}

View File

@ -1,22 +0,0 @@
package com.tommasoberlose.anotherwidget.receivers
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
class PlayerReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d("ciao", "player ok")
// val cmd = intent.getStringExtra("command")
// Log.v("tag ", "$action / $cmd")
// val artist = intent.getStringExtra("artist")
// val album = intent.getStringExtra("album")
// val track = intent.getStringExtra("track")
// Log.v("tag", "$artist:$album:$track")
}
}

View File

@ -26,6 +26,7 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.Navigation import androidx.navigation.Navigation
import com.chibatching.kotpref.Kotpref
import com.google.android.material.badge.BadgeDrawable import com.google.android.material.badge.BadgeDrawable
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import com.karumi.dexter.Dexter import com.karumi.dexter.Dexter

View File

@ -129,12 +129,9 @@ class CalendarTabFragment : Fragment() {
}) })
viewModel.showNextEvent.observe(viewLifecycleOwner, Observer { viewModel.showNextEvent.observe(viewLifecycleOwner, Observer {
show_multiple_events_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
})
viewModel.dateFormat.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
date_format_label?.text = DateHelper.getDateText(requireContext(), Calendar.getInstance()) show_multiple_events_label?.text =
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
} }
}) })
@ -278,7 +275,7 @@ class CalendarTabFragment : Fragment() {
action_show_until.setOnClickListener { action_show_until.setOnClickListener {
if (Preferences.showEvents) { if (Preferences.showEvents) {
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_show_until_title)).setSelectedValue(Preferences.showUntil) val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_show_until_title)).setSelectedValue(Preferences.showUntil)
intArrayOf(6,7,0,1,2).forEach { intArrayOf(6,7,0,1,2,3).forEach {
dialog.addItem(getString(SettingsStringHelper.getShowUntilString(it)), it) dialog.addItem(getString(SettingsStringHelper.getShowUntilString(it)), it)
} }
dialog.addOnSelectItemListener { value -> dialog.addOnSelectItemListener { value ->
@ -287,27 +284,6 @@ class CalendarTabFragment : Fragment() {
} }
} }
action_date_format.setOnClickListener {
if (Preferences.showEvents) {
val now = Calendar.getInstance()
val dialog = BottomSheetMenu<String>(requireContext(), header = getString(R.string.settings_date_format_title)).setSelectedValue(Preferences.dateFormat)
dialog.addItem(DateHelper.getDefaultDateText(requireContext(), now), "")
if (Preferences.dateFormat != "") {
dialog.addItem(DateHelper.getDateText(requireContext(), now), Preferences.dateFormat)
}
dialog.addItem(getString(R.string.custom_date_format), "-")
dialog.addOnSelectItemListener { value ->
if (value == "-") {
startActivity(Intent(requireContext(), CustomDateActivity::class.java))
} else {
Preferences.dateFormat = value
}
}.show()
}
}
action_open_event_details.setOnClickListener { action_open_event_details.setOnClickListener {
if (Preferences.showEvents) { if (Preferences.showEvents) {
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_event_app_title)).setSelectedValue(Preferences.openEventDetails) BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_event_app_title)).setSelectedValue(Preferences.openEventDetails)

View File

@ -104,6 +104,12 @@ class ClockTabFragment : Fragment() {
} }
}) })
viewModel.showAMPMIndicator.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
ampm_indicator_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
}
})
viewModel.clockTextColor.observe(viewLifecycleOwner, Observer { viewModel.clockTextColor.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
if (Preferences.clockTextAlpha == "00") { if (Preferences.clockTextAlpha == "00") {
@ -168,6 +174,15 @@ class ClockTabFragment : Fragment() {
}.show() }.show()
} }
action_ampm_indicator_size.setOnClickListener {
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_ampm_indicator_title)).setSelectedValue(Preferences.showAMPMIndicator)
.addItem(getString(R.string.settings_visible), true)
.addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value ->
Preferences.showAMPMIndicator = value
}.show()
}
action_clock_text_color.setOnClickListener { action_clock_text_color.setOnClickListener {
BottomSheetColorPicker(requireContext(), BottomSheetColorPicker(requireContext(),
colors = colors, colors = colors,

View File

@ -21,7 +21,9 @@ import com.tommasoberlose.anotherwidget.global.RequestCode
import com.tommasoberlose.anotherwidget.helpers.ColorHelper import com.tommasoberlose.anotherwidget.helpers.ColorHelper
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
import com.tommasoberlose.anotherwidget.helpers.DateHelper
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
import com.tommasoberlose.anotherwidget.ui.activities.CustomDateActivity
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
import kotlinx.android.synthetic.main.fragment_general_settings.* import kotlinx.android.synthetic.main.fragment_general_settings.*
@ -29,6 +31,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.util.*
class GeneralTabFragment : Fragment() { class GeneralTabFragment : Fragment() {
@ -141,6 +144,12 @@ class GeneralTabFragment : Fragment() {
} }
}) })
viewModel.dateFormat.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
date_format_label?.text = DateHelper.getDateText(requireContext(), Calendar.getInstance())
}
})
viewModel.customFont.observe(viewLifecycleOwner, Observer { viewModel.customFont.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
custom_font_label?.text = getString(SettingsStringHelper.getCustomFontLabel(it)) custom_font_label?.text = getString(SettingsStringHelper.getCustomFontLabel(it))
@ -148,7 +157,10 @@ class GeneralTabFragment : Fragment() {
}) })
viewModel.showDividers.observe(viewLifecycleOwner, Observer { viewModel.showDividers.observe(viewLifecycleOwner, Observer {
show_dividers_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible) maintainScrollPosition {
show_dividers_label?.text =
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
}
}) })
} }
@ -164,7 +176,7 @@ class GeneralTabFragment : Fragment() {
private fun setupListener() { private fun setupListener() {
action_main_text_size.setOnClickListener { action_main_text_size.setOnClickListener {
val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_main_text_size)).setSelectedValue(Preferences.textMainSize) val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_main_text_size)).setSelectedValue(Preferences.textMainSize)
(32 downTo 10).filter { it % 2 == 0 }.forEach { (40 downTo 10).filter { it % 2 == 0 }.forEach {
dialog.addItem("${it}sp", it.toFloat()) dialog.addItem("${it}sp", it.toFloat())
} }
dialog.addOnSelectItemListener { value -> dialog.addOnSelectItemListener { value ->
@ -174,7 +186,7 @@ class GeneralTabFragment : Fragment() {
action_second_text_size.setOnClickListener { action_second_text_size.setOnClickListener {
val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_second_text_size)).setSelectedValue(Preferences.textSecondSize) val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_second_text_size)).setSelectedValue(Preferences.textSecondSize)
(28 downTo 10).filter { it % 2 == 0 }.forEach { (40 downTo 10).filter { it % 2 == 0 }.forEach {
dialog.addItem("${it}sp", it.toFloat()) dialog.addItem("${it}sp", it.toFloat())
} }
dialog.addOnSelectItemListener { value -> dialog.addOnSelectItemListener { value ->
@ -199,6 +211,27 @@ class GeneralTabFragment : Fragment() {
).show() ).show()
} }
action_date_format.setOnClickListener {
if (Preferences.showEvents) {
val now = Calendar.getInstance()
val dialog = BottomSheetMenu<String>(requireContext(), header = getString(R.string.settings_date_format_title)).setSelectedValue(Preferences.dateFormat)
dialog.addItem(DateHelper.getDefaultDateText(requireContext(), now), "")
if (Preferences.dateFormat != "") {
dialog.addItem(DateHelper.getDateText(requireContext(), now), Preferences.dateFormat)
}
dialog.addItem(getString(R.string.custom_date_format), "-")
dialog.addOnSelectItemListener { value ->
if (value == "-") {
startActivity(Intent(requireContext(), CustomDateActivity::class.java))
} else {
Preferences.dateFormat = value
}
}.show()
}
}
action_background_color.setOnClickListener { action_background_color.setOnClickListener {
BottomSheetColorPicker(requireContext(), BottomSheetColorPicker(requireContext(),
colors = colors, colors = colors,

View File

@ -1,44 +1,51 @@
package com.tommasoberlose.anotherwidget.ui.fragments package com.tommasoberlose.anotherwidget.ui.fragments
import android.Manifest
import android.app.Activity
import android.app.AlarmManager import android.app.AlarmManager
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.ItemTouchHelper import com.google.android.gms.auth.api.signin.GoogleSignIn
import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import androidx.recyclerview.widget.RecyclerView import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import androidx.recyclerview.widget.RecyclerView.ViewHolder import com.google.android.gms.common.api.ApiException
import com.karumi.dexter.Dexter
import com.karumi.dexter.MultiplePermissionsReport
import com.karumi.dexter.PermissionToken
import com.karumi.dexter.listener.PermissionRequest
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
import com.tommasoberlose.anotherwidget.components.CustomNotesDialog
import com.tommasoberlose.anotherwidget.components.GlanceProviderSortMenu
import com.tommasoberlose.anotherwidget.databinding.FragmentGlanceSettingsBinding import com.tommasoberlose.anotherwidget.databinding.FragmentGlanceSettingsBinding
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.AlarmHelper import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
import com.tommasoberlose.anotherwidget.helpers.GlanceProviderHelper
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
import com.tommasoberlose.anotherwidget.models.GlanceProvider import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver.Companion.FITNESS_OPTIONS
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import kotlinx.android.synthetic.main.fragment_glance_settings.* import kotlinx.android.synthetic.main.fragment_glance_settings.*
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.idik.lib.slimadapter.SlimAdapter
import java.util.*
class GlanceTabFragment : Fragment() { class GlanceTabFragment : Fragment() {
@ -48,7 +55,6 @@ class GlanceTabFragment : Fragment() {
} }
private lateinit var viewModel: MainViewModel private lateinit var viewModel: MainViewModel
private lateinit var adapter: SlimAdapter
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -73,65 +79,6 @@ class GlanceTabFragment : Fragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
list.setHasFixedSize(true)
val mLayoutManager = LinearLayoutManager(requireContext())
list.layoutManager = mLayoutManager
adapter = SlimAdapter.create()
adapter
.register<String>(R.layout.glance_provider_item) { item, injector ->
injector
.text(R.id.title, item)
}
.register<GlanceProvider>(R.layout.glance_provider_item) { item, injector ->
injector
.text(R.id.title, item.title)
.with<ImageView>(R.id.icon) {
it.setImageDrawable(ContextCompat.getDrawable(requireContext(), item.icon))
}
.with<TextView>(R.id.label) {
it.isVisible = item.label != ""
it.text = item.label
}
}
.attachTo(list)
adapter.updateData(
GlanceProviderHelper.getGlanceProviders()
.mapNotNull { GlanceProviderHelper.getGlanceProviderById(requireContext(), it) }
)
val mIth = ItemTouchHelper(
object : ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP or ItemTouchHelper.DOWN,
ItemTouchHelper.LEFT
) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: ViewHolder, target: ViewHolder
): Boolean {
val fromPos = viewHolder.adapterPosition
val toPos = target.adapterPosition
// move item in `fromPos` to `toPos` in adapter.
adapter.notifyItemMoved(fromPos, toPos)
val list = GlanceProviderHelper.getGlanceProviders()
Collections.swap(list, fromPos, toPos)
GlanceProviderHelper.saveGlanceProviderOrder(list)
return true
}
override fun onSwiped(
viewHolder: ViewHolder,
direction: Int
) {
// remove from adapter
}
})
mIth.attachToRecyclerView(list)
setupListener() setupListener()
updateNextAlarmWarningUi() updateNextAlarmWarningUi()
} }
@ -142,15 +89,40 @@ class GlanceTabFragment : Fragment() {
) { ) {
viewModel.showGlance.observe(viewLifecycleOwner, Observer { viewModel.showGlance.observe(viewLifecycleOwner, Observer {
binding.isGlanceVisible = it maintainScrollPosition {
binding.isGlanceVisible = it
}
}) })
viewModel.showMusic.observe(viewLifecycleOwner, Observer { viewModel.showMusic.observe(viewLifecycleOwner, Observer {
checkNotificationPermission() maintainScrollPosition {
checkNotificationPermission()
}
}) })
viewModel.showNextAlarm.observe(viewLifecycleOwner, Observer { viewModel.showNextAlarm.observe(viewLifecycleOwner, Observer {
updateNextAlarmWarningUi() maintainScrollPosition {
updateNextAlarmWarningUi()
}
})
viewModel.showBatteryCharging.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_low_battery_level_warning_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
}
})
viewModel.showDailySteps.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_steps_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
}
checkFitnessPermission()
})
viewModel.customInfo.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_custom_notes_label?.text = if (it == "") getString(R.string.settings_not_visible) else it
}
}) })
} }
@ -165,6 +137,11 @@ class GlanceTabFragment : Fragment() {
Preferences.showGlance = enabled Preferences.showGlance = enabled
} }
action_sort_glance_providers.setOnClickListener {
GlanceProviderSortMenu(requireContext())
.show()
}
action_show_music.setOnClickListener { action_show_music.setOnClickListener {
if (Preferences.showGlance) { if (Preferences.showGlance) {
BottomSheetMenu<Boolean>( BottomSheetMenu<Boolean>(
@ -192,6 +169,50 @@ class GlanceTabFragment : Fragment() {
}.show() }.show()
} }
} }
action_show_low_battery_level_warning.setOnClickListener {
if (Preferences.showGlance) {
BottomSheetMenu<Boolean>(
requireContext(),
header = getString(R.string.settings_low_battery_level_title)
).setSelectedValue(Preferences.showBatteryCharging)
.addItem(getString(R.string.settings_visible), true)
.addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value ->
Preferences.showBatteryCharging = value
}.show()
}
}
action_show_steps.setOnClickListener {
if (Preferences.showGlance) {
BottomSheetMenu<Boolean>(
requireContext(),
header = getString(R.string.settings_daily_steps_title)
).setSelectedValue(Preferences.showDailySteps)
.addItem(getString(R.string.settings_visible), true)
.addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value ->
if (value) {
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(requireContext())
if (!GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS)) {
val mGoogleSignInClient = GoogleSignIn.getClient(requireActivity(), GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).addExtension(FITNESS_OPTIONS).build())
startActivityForResult(mGoogleSignInClient.signInIntent, 2)
} else {
Preferences.showDailySteps = true
}
} else {
Preferences.showDailySteps = false
}
}.show()
}
}
action_show_custom_notes.setOnClickListener {
if (Preferences.showGlance) {
CustomNotesDialog(requireContext()).show()
}
}
} }
private fun updateNextAlarmWarningUi() { private fun updateNextAlarmWarningUi() {
@ -204,15 +225,11 @@ class GlanceTabFragment : Fragment() {
} catch (e: Exception) { } catch (e: Exception) {
alarm.showIntent?.creatorPackage ?: "" alarm.showIntent?.creatorPackage ?: ""
} }
maintainScrollPosition { show_next_alarm_warning.text =
show_next_alarm_warning.text = getString(R.string.next_alarm_warning).format(appNameOrPackage)
getString(R.string.next_alarm_warning).format(appNameOrPackage)
}
} else { } else {
maintainScrollPosition { show_next_alarm_label?.text = if (Preferences.showNextAlarm) getString(R.string.settings_visible) else getString(
show_next_alarm_label?.text = if (Preferences.showNextAlarm) getString(R.string.settings_visible) else getString(
R.string.settings_not_visible) R.string.settings_not_visible)
}
} }
} }
} }
@ -237,7 +254,7 @@ class GlanceTabFragment : Fragment() {
if (NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName)) { if (NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName)) {
notification_permission_alert?.isVisible = false notification_permission_alert?.isVisible = false
MediaPlayerHelper.updatePlayingMediaInfo(requireContext()) MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
show_music_label?.text = if (Preferences.showMusic) getString(R.string.settings_show_music_enabled_subtitle) else getString(R.string.settings_show_music_disabled_subtitle) show_music_label?.text = if (Preferences.showMusic) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
} else if (Preferences.showMusic) { } else if (Preferences.showMusic) {
notification_permission_alert?.isVisible = true notification_permission_alert?.isVisible = true
show_music_label?.text = getString(R.string.settings_request_notification_access) show_music_label?.text = getString(R.string.settings_request_notification_access)
@ -245,11 +262,93 @@ class GlanceTabFragment : Fragment() {
activity?.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS")) activity?.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
} }
} else { } else {
show_music_label?.text = getString(R.string.settings_show_music_disabled_subtitle) show_music_label?.text = getString(R.string.settings_not_visible)
notification_permission_alert?.isVisible = false notification_permission_alert?.isVisible = false
} }
} }
private fun checkFitnessPermission() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || activity?.checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION) == true) {
fitness_permission_alert?.isVisible = false
if (Preferences.showDailySteps) {
ActivityDetectionReceiver.registerFence(requireContext())
} else {
ActivityDetectionReceiver.unregisterFence(requireContext())
}
show_steps_label?.text = if (Preferences.showDailySteps) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
} else if (Preferences.showDailySteps) {
ActivityDetectionReceiver.unregisterFence(requireContext())
fitness_permission_alert?.isVisible = true
show_steps_label?.text = getString(R.string.settings_request_fitness_access)
fitness_permission_alert?.setOnClickListener {
requireFitnessPermission()
}
} else {
ActivityDetectionReceiver.unregisterFence(requireContext())
show_steps_label?.text = getString(R.string.settings_not_visible)
fitness_permission_alert?.isVisible = false
}
}
override fun onActivityResult(
requestCode: Int,
resultCode: Int,
data: Intent?
) {
when (requestCode) {
1 -> {
if (resultCode == Activity.RESULT_OK) {
checkFitnessPermission()
} else {
Preferences.showDailySteps = false
}
}
2-> {
try {
val account: GoogleSignInAccount? = GoogleSignIn.getSignedInAccountFromIntent(data).getResult(ApiException::class.java)
if (!GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS)) {
GoogleSignIn.requestPermissions(
requireActivity(),
1,
account,
FITNESS_OPTIONS)
} else {
checkFitnessPermission()
}
} catch (e: ApiException) {
e.printStackTrace()
Preferences.showDailySteps = false
}
}
}
}
private fun requireFitnessPermission() {
Dexter.withContext(requireContext())
.withPermissions(
"com.google.android.gms.permission.ACTIVITY_RECOGNITION",
"android.gms.permission.ACTIVITY_RECOGNITION",
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACTIVITY_RECOGNITION else "com.google.android.gms.permission.ACTIVITY_RECOGNITION"
).withListener(object: MultiplePermissionsListener {
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
report?.let {
if (report.areAllPermissionsGranted()){
checkFitnessPermission()
}
}
}
override fun onPermissionRationaleShouldBeShown(
permissions: MutableList<PermissionRequest>?,
token: PermissionToken?
) {
// Remember to invoke this method when the custom rationale is closed
// or just by default if you don't want to use any custom rationale.
token?.continuePermissionRequest()
}
})
.check()
}
private fun maintainScrollPosition(callback: () -> Unit) { private fun maintainScrollPosition(callback: () -> Unit) {
val scrollPosition = scrollView.scrollY val scrollPosition = scrollView.scrollY
callback.invoke() callback.invoke()

View File

@ -124,142 +124,156 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
private fun updateUI() { private fun updateUI() {
uiJob?.cancel() uiJob?.cancel()
if (preview != null) {
preview.clearAnimation()
time_container.clearAnimation()
if (Preferences.showPreview) { if (Preferences.showPreview) {
preview.setCardBackgroundColor( preview.setCardBackgroundColor(
ContextCompat.getColor( ContextCompat.getColor(
requireContext(), requireContext(),
if (ColorHelper.getFontColor() if (ColorHelper.getFontColor()
.isColorDark() .isColorDark()
) android.R.color.white else R.color.colorAccent ) android.R.color.white else R.color.colorAccent
)
)
widget_shape_background.setImageDrawable(BitmapHelper.getTintedDrawable(requireContext(), R.drawable.card_background, ColorHelper.getBackgroundColor()))
uiJob = viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
val generatedView = MainWidget.generateWidgetView(requireContext())
withContext(Dispatchers.Main) {
generatedView.measure(0, 0)
preview.measure(0, 0)
}
val bitmap = BitmapHelper.getBitmapFromView(
generatedView,
if (preview.width > 0) preview.width else generatedView.measuredWidth,
generatedView.measuredHeight
)
withContext(Dispatchers.Main) {
// Clock
time.setTextColor(ColorHelper.getClockFontColor())
time_am_pm.setTextColor(ColorHelper.getClockFontColor())
time.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(requireContext())
) )
time_am_pm.setTextSize( )
TypedValue.COMPLEX_UNIT_SP, widget_shape_background?.setImageDrawable(
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2 BitmapHelper.getTintedDrawable(
requireContext(),
R.drawable.card_background,
ColorHelper.getBackgroundColor()
) )
)
uiJob = viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
val generatedView = MainWidget.generateWidgetView(requireContext())
// Clock bottom margin withContext(Dispatchers.Main) {
clock_bottom_margin_none.isVisible = generatedView.measure(0, 0)
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value preview.measure(0, 0)
clock_bottom_margin_small.isVisible = }
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value
clock_bottom_margin_medium.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value
clock_bottom_margin_large.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value
if ((Preferences.showClock && !time_container.isVisible) || (!Preferences.showClock && time_container.isVisible)) { val bitmap = BitmapHelper.getBitmapFromView(
if (Preferences.showClock) { generatedView,
if (preview.width > 0) preview.width else generatedView.measuredWidth,
generatedView.measuredHeight
)
withContext(Dispatchers.Main) {
// Clock
time.setTextColor(ColorHelper.getClockFontColor())
time_am_pm.setTextColor(ColorHelper.getClockFontColor())
time.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(requireContext())
)
time_am_pm.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2
)
time_am_pm.isVisible = Preferences.showAMPMIndicator
// Clock bottom margin
clock_bottom_margin_none.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value
clock_bottom_margin_small.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value
clock_bottom_margin_medium.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value
clock_bottom_margin_large.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value
if ((Preferences.showClock && !time_container.isVisible) || (!Preferences.showClock && time_container.isVisible)) {
if (Preferences.showClock) {
time_container.layoutParams = time_container.layoutParams.apply {
height = RelativeLayout.LayoutParams.WRAP_CONTENT
}
time_container.measure(0, 0)
}
val initialHeight = time_container.measuredHeight
ValueAnimator.ofFloat(
if (Preferences.showClock) 0f else 1f,
if (Preferences.showClock) 1f else 0f
).apply {
duration = 500L
addUpdateListener {
val animatedValue = animatedValue as Float
time_container.layoutParams =
time_container.layoutParams.apply {
height = (initialHeight * animatedValue).toInt()
}
time.alpha = animatedValue
}
addListener(
onStart = {
if (Preferences.showClock) {
time_container.isVisible = true
}
},
onEnd = {
if (!Preferences.showClock) {
time_container.isVisible = false
}
}
)
}.start()
ValueAnimator.ofInt(
preview.height,
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
requireContext()
) else 0
).apply {
duration = 500L
addUpdateListener {
val animatedValue = animatedValue as Int
val layoutParams = preview.layoutParams
layoutParams.height = animatedValue
preview.layoutParams = layoutParams
}
}.start()
} else {
time_container.layoutParams = time_container.layoutParams.apply { time_container.layoutParams = time_container.layoutParams.apply {
height = RelativeLayout.LayoutParams.WRAP_CONTENT height = RelativeLayout.LayoutParams.WRAP_CONTENT
} }
time_container.measure(0, 0) time_container.measure(0, 0)
} }
val initialHeight = time_container.measuredHeight
ValueAnimator.ofFloat(
if (Preferences.showClock) 0f else 1f,
if (Preferences.showClock) 1f else 0f
).apply {
duration = 500L
addUpdateListener {
val animatedValue = animatedValue as Float
time_container.layoutParams = time_container.layoutParams.apply {
height = (initialHeight * animatedValue).toInt()
}
}
addListener(
onStart = {
if (Preferences.showClock) {
time_container.isVisible = true
}
},
onEnd = {
if (!Preferences.showClock) {
time_container.isVisible = false
}
}
)
}.start()
ValueAnimator.ofInt( if (preview.height == 0) {
preview.height, ValueAnimator.ofInt(
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel( preview.height,
requireContext() PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
) else 0 requireContext()
).apply { ) else 0
duration = 500L ).apply {
addUpdateListener { duration = 300L
val animatedValue = animatedValue as Int addUpdateListener {
val layoutParams = preview.layoutParams val animatedValue = animatedValue as Int
layoutParams.height = animatedValue val layoutParams = preview.layoutParams
preview.layoutParams = layoutParams layoutParams.height = animatedValue
} preview.layoutParams = layoutParams
}.start() }
} else { }.start()
time_container.layoutParams = time_container.layoutParams.apply {
height = RelativeLayout.LayoutParams.WRAP_CONTENT
} }
time_container.measure(0, 0)
}
if (preview.height == 0) { widget_loader.animate().scaleX(0f).scaleY(0f).alpha(0f).setDuration(200L)
ValueAnimator.ofInt( .start()
preview.height, bitmap_container.setImageBitmap(bitmap)
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel( widget.animate().alpha(1f).start()
requireContext()
) else 0
).apply {
duration = 300L
addUpdateListener {
val animatedValue = animatedValue as Int
val layoutParams = preview.layoutParams
layoutParams.height = animatedValue
preview.layoutParams = layoutParams
}
}.start()
} }
widget_loader.animate().scaleX(0f).scaleY(0f).alpha(0f).setDuration(200L).start()
bitmap_container.setImageBitmap(bitmap)
widget.animate().alpha(1f).start()
} }
} else {
ValueAnimator.ofInt(
preview.height,
0
).apply {
duration = 300L
addUpdateListener {
val animatedValue = animatedValue as Int
val layoutParams = preview.layoutParams
layoutParams.height = animatedValue
preview.layoutParams = layoutParams
}
}.start()
} }
} else {
ValueAnimator.ofInt(
preview.height,
0
).apply {
duration = 300L
addUpdateListener {
val animatedValue = animatedValue as Int
val layoutParams = preview.layoutParams
layoutParams.height = animatedValue
preview.layoutParams = layoutParams
}
}.start()
} }
showErrorBadge() showErrorBadge()
@ -276,8 +290,16 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
val metrics = DisplayMetrics() val metrics = DisplayMetrics()
act.windowManager.defaultDisplay.getMetrics(metrics) act.windowManager.defaultDisplay.getMetrics(metrics)
height = metrics.heightPixels var newHeight = metrics.heightPixels
width = (wallpaper?.intrinsicWidth ?: 1) * metrics.heightPixels / (wallpaper?.intrinsicWidth ?: 1) var newWidth = (wallpaper?.intrinsicWidth ?: 1) * metrics.heightPixels / (wallpaper?.intrinsicHeight ?: 1)
if (newWidth < metrics.widthPixels) {
newWidth = metrics.widthPixels
newHeight = (wallpaper?.intrinsicHeight ?: 1) * metrics.widthPixels / (wallpaper?.intrinsicWidth ?: 1)
}
height = newHeight
width = newWidth
} }
} }
}) })
@ -312,11 +334,6 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
}?.isVisible = Preferences.showMusic && !NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName) }?.isVisible = Preferences.showMusic && !NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName)
} }
override fun onSharedPreferenceChanged(preferences: SharedPreferences, p1: String) {
updateUI()
MainWidget.updateWidget(requireContext())
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
Preferences.preferences.registerOnSharedPreferenceChangeListener(this) Preferences.preferences.registerOnSharedPreferenceChangeListener(this)
@ -331,10 +348,29 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
super.onPause() super.onPause()
} }
var delayJob: Job? = null
override fun onSharedPreferenceChanged(preferences: SharedPreferences, p1: String) {
delayJob?.cancel()
delayJob = lifecycleScope.launch(Dispatchers.IO) {
delay(200)
withContext(Dispatchers.Main) {
updateUI()
}
}
MainWidget.updateWidget(requireContext())
}
class UpdateUiMessageEvent class UpdateUiMessageEvent
@Subscribe(threadMode = ThreadMode.MAIN) @Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(ignore: UpdateUiMessageEvent?) { fun onMessageEvent(ignore: UpdateUiMessageEvent?) {
updateUI() delayJob?.cancel()
delayJob = lifecycleScope.launch(Dispatchers.IO) {
delay(200)
withContext(Dispatchers.Main) {
updateUI()
}
}
} }
} }

View File

@ -4,6 +4,7 @@ import android.Manifest
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup

View File

@ -33,6 +33,7 @@ class MainViewModel : ViewModel() {
val clockTextSize = Preferences.asLiveData(Preferences::clockTextSize) val clockTextSize = Preferences.asLiveData(Preferences::clockTextSize)
val clockTextColor = Preferences.asLiveData(Preferences::clockTextColor) val clockTextColor = Preferences.asLiveData(Preferences::clockTextColor)
val clockTextAlpha = Preferences.asLiveData(Preferences::clockTextAlpha) val clockTextAlpha = Preferences.asLiveData(Preferences::clockTextAlpha)
val showAMPMIndicator = Preferences.asLiveData(Preferences::showAMPMIndicator)
val clockAppName = Preferences.asLiveData(Preferences::clockAppName) val clockAppName = Preferences.asLiveData(Preferences::clockAppName)
val dateFormat = Preferences.asLiveData(Preferences::dateFormat) val dateFormat = Preferences.asLiveData(Preferences::dateFormat)
@ -56,6 +57,9 @@ class MainViewModel : ViewModel() {
val showGlance = Preferences.asLiveData(Preferences::showGlance) val showGlance = Preferences.asLiveData(Preferences::showGlance)
val showMusic = Preferences.asLiveData(Preferences::showMusic) val showMusic = Preferences.asLiveData(Preferences::showMusic)
val showNextAlarm = Preferences.asLiveData(Preferences::showNextAlarm) val showNextAlarm = Preferences.asLiveData(Preferences::showNextAlarm)
val showBatteryCharging = Preferences.asLiveData(Preferences::showBatteryCharging)
val showDailySteps = Preferences.asLiveData(Preferences::showDailySteps)
val customInfo = Preferences.asLiveData(Preferences::customNotes)
// Advanced Settings // Advanced Settings
val darkThemePreference = Preferences.asLiveData(Preferences::darkThemePreference) val darkThemePreference = Preferences.asLiveData(Preferences::darkThemePreference)

View File

@ -12,7 +12,6 @@ import android.graphics.Color
import android.graphics.Typeface import android.graphics.Typeface
import android.os.Bundle import android.os.Bundle
import android.text.format.DateUtils import android.text.format.DateUtils
import android.util.Log
import android.util.TypedValue import android.util.TypedValue
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
@ -261,14 +260,57 @@ class MainWidget : AppWidgetProvider() {
views.setViewVisibility(R.id.empty_layout_rect, View.GONE) views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE) views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
} else if (MediaPlayerHelper.isSomeonePlaying(context)) { } else if (GlanceProviderHelper.showGlanceProviders(context)) {
val musicIntent = PendingIntent.getActivity( loop@ for (provider:Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders()) {
context, when (provider) {
widgetID, Constants.GlanceProviderId.PLAYING_SONG -> {
IntentHelper.getMusicIntent(context), if (MediaPlayerHelper.isSomeonePlaying(context)) {
0 val musicIntent = PendingIntent.getActivity(
) context,
views.setOnClickPendingIntent(R.id.second_row_rect, musicIntent) widgetID,
IntentHelper.getMusicIntent(context),
0
)
views.setOnClickPendingIntent(R.id.second_row_rect, musicIntent)
break@loop
}
}
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
if (Preferences.showNextAlarm && nextAlarm != "") {
val alarmIntent = PendingIntent.getActivity(
context,
widgetID,
IntentHelper.getClockIntent(context),
0
)
views.setOnClickPendingIntent(R.id.second_row_rect, alarmIntent)
break@loop
}
}
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
if (Preferences.isBatteryLevelLow) {
val alarmIntent = PendingIntent.getActivity(
context,
widgetID,
IntentHelper.getClockIntent(context),
0
)
views.setOnClickPendingIntent(R.id.second_row_rect, alarmIntent)
break@loop
}
}
Constants.GlanceProviderId.CUSTOM_INFO -> {
if (Preferences.customNotes.isNotEmpty()) {
break@loop
}
}
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) {
break@loop
}
}
}
}
views.setImageViewBitmap( views.setImageViewBitmap(
R.id.next_event_rect, R.id.next_event_rect,
@ -279,31 +321,8 @@ class MainWidget : AppWidgetProvider() {
R.id.second_row_rect, R.id.second_row_rect,
BitmapHelper.getBitmapFromView(v.second_row, draw = false) BitmapHelper.getBitmapFromView(v.second_row, draw = false)
) )
views.setViewVisibility(R.id.second_row_rect, View.VISIBLE) views.setViewVisibility(R.id.second_row_rect, View.VISIBLE)
views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
views.setOnClickPendingIntent(R.id.next_event_rect, calPIntent)
} else if (Preferences.showNextAlarm && nextAlarm != "") {
val alarmIntent = PendingIntent.getActivity(
context,
widgetID,
IntentHelper.getClockIntent(context),
0
)
views.setOnClickPendingIntent(R.id.second_row_rect, alarmIntent)
views.setImageViewBitmap(
R.id.next_event_rect,
BitmapHelper.getBitmapFromView(v.next_event, draw = false)
)
views.setImageViewBitmap(
R.id.second_row_rect,
BitmapHelper.getBitmapFromView(v.second_row, draw = false)
)
views.setViewVisibility(R.id.second_row_rect, View.VISIBLE)
views.setViewVisibility(R.id.empty_layout_rect, View.GONE) views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE) views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
views.setOnClickPendingIntent(R.id.next_event_rect, calPIntent) views.setOnClickPendingIntent(R.id.next_event_rect, calPIntent)
@ -346,7 +365,7 @@ class MainWidget : AppWidgetProvider() {
BitmapHelper.getBitmapFromView(v.calendar_weather, draw = false) BitmapHelper.getBitmapFromView(v.calendar_weather, draw = false)
) )
if (WidgetHelper.showSpecialWeather(context)) { if (GlanceProviderHelper.showGlanceProviders(context)) {
views.setViewVisibility(R.id.calendar_weather_rect, View.GONE) views.setViewVisibility(R.id.calendar_weather_rect, View.GONE)
} else { } else {
views.setViewVisibility(R.id.special_weather_rect, View.GONE) views.setViewVisibility(R.id.special_weather_rect, View.GONE)
@ -394,7 +413,7 @@ class MainWidget : AppWidgetProvider() {
views.setOnClickPendingIntent(R.id.time, clockPIntent) views.setOnClickPendingIntent(R.id.time, clockPIntent)
views.setOnClickPendingIntent(R.id.time_am_pm, clockPIntent) views.setOnClickPendingIntent(R.id.time_am_pm, clockPIntent)
views.setViewVisibility(R.id.time, View.VISIBLE) views.setViewVisibility(R.id.time, View.VISIBLE)
views.setViewVisibility(R.id.time_am_pm, View.VISIBLE) views.setViewVisibility(R.id.time_am_pm, if (Preferences.showAMPMIndicator) View.VISIBLE else View.GONE)
views.setViewVisibility( views.setViewVisibility(
R.id.clock_bottom_margin_none, R.id.clock_bottom_margin_none,
@ -499,26 +518,69 @@ class MainWidget : AppWidgetProvider() {
v.empty_layout.visibility = View.GONE v.empty_layout.visibility = View.GONE
v.calendar_layout.visibility = View.VISIBLE v.calendar_layout.visibility = View.VISIBLE
} else if (MediaPlayerHelper.isSomeonePlaying(context)) { } else if (GlanceProviderHelper.showGlanceProviders(context)) {
v.second_row_icon.setImageDrawable( v.second_row_icon.isVisible = true
ContextCompat.getDrawable( loop@ for (provider:Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders()) {
context, when (provider) {
R.drawable.round_music_note Constants.GlanceProviderId.PLAYING_SONG -> {
) if (MediaPlayerHelper.isSomeonePlaying(context)) {
) v.second_row_icon.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.round_music_note
)
)
v.next_event_date.text = MediaPlayerHelper.getMediaInfo()
break@loop
}
}
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
if (Preferences.showNextAlarm && nextAlarm != "") {
v.second_row_icon.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.round_alarm
)
)
v.next_event_date.text = AlarmHelper.getNextAlarm(context)
break@loop
}
}
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
if (Preferences.isBatteryLevelLow) {
v.second_row_icon.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.round_battery_charging_full
)
)
v.next_event_date.text = context.getString(R.string.battery_low_warning)
break@loop
}
}
Constants.GlanceProviderId.CUSTOM_INFO -> {
if (Preferences.customNotes.isNotEmpty()) {
v.second_row_icon.isVisible = false
v.next_event_date.text = Preferences.customNotes
break@loop
}
}
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) {
v.second_row_icon.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.round_directions_walk
)
)
v.next_event_date.text = "${Preferences.googleFitSteps}"
break@loop
}
}
}
}
v.next_event.text = DateHelper.getDateText(context, now) v.next_event.text = DateHelper.getDateText(context, now)
v.next_event_date.text = MediaPlayerHelper.getMediaInfo()
v.empty_layout.visibility = View.GONE
v.calendar_layout.visibility = View.VISIBLE
} else if (Preferences.showNextAlarm && nextAlarm != "") {
v.second_row_icon.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.round_alarm
)
)
v.next_event.text = DateHelper.getDateText(context, now)
v.next_event_date.text = AlarmHelper.getNextAlarm(context)
v.empty_layout.visibility = View.GONE v.empty_layout.visibility = View.GONE
v.calendar_layout.visibility = View.VISIBLE v.calendar_layout.visibility = View.VISIBLE
} }
@ -626,7 +688,7 @@ class MainWidget : AppWidgetProvider() {
v.calendar_temp.text = currentTemp v.calendar_temp.text = currentTemp
v.special_temp.text = currentTemp v.special_temp.text = currentTemp
if (WidgetHelper.showSpecialWeather(context)) { if (GlanceProviderHelper.showGlanceProviders(context)) {
v.calendar_weather.visibility = View.GONE v.calendar_weather.visibility = View.GONE
} else { } else {
v.special_weather.visibility = View.GONE v.special_weather.visibility = View.GONE

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 617 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

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