Compare commits
23 Commits
v2.0.14-be
...
v2.0.15-be
Author | SHA1 | Date | |
---|---|---|---|
a1a6f9f607 | |||
815a88a079 | |||
1c1f55e20a | |||
5259a81cfb | |||
3b963dae1c | |||
878ddcb05e | |||
0ce446f0ef | |||
c5fefb0e06 | |||
c5eb5358aa | |||
c4a16224f0 | |||
122c0627d9 | |||
6d80ec97a8 | |||
1c7df585fe | |||
9f4cdc950b | |||
0a0c5a90a7 | |||
011517e12d | |||
fdd82e0f91 | |||
abafe108c6 | |||
03f08e4f08 | |||
9ecb9b4819 | |||
2bb30aae69 | |||
01d219d38c | |||
6c7831d972 |
12
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
custom: ['paypal.me/tommasoberlose']
|
BIN
.idea/caches/build_file_checksums.ser
generated
1
.idea/gradle.xml
generated
@ -14,6 +14,7 @@
|
|||||||
</set>
|
</set>
|
||||||
</option>
|
</option>
|
||||||
<option name="resolveModulePerSourceSet" value="false" />
|
<option name="resolveModulePerSourceSet" value="false" />
|
||||||
|
<option name="useQualifiedModuleNames" value="true" />
|
||||||
</GradleProjectSettings>
|
</GradleProjectSettings>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
2
.idea/misc.xml
generated
@ -61,7 +61,7 @@
|
|||||||
</profile-state>
|
</profile-state>
|
||||||
</entry>
|
</entry>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
4
.idea/modules.xml
generated
@ -2,8 +2,8 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/Another_Widget.iml" filepath="$PROJECT_DIR$/.idea/modules/Another_Widget.iml" group="Another_Widget" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/Another_Widget.iml" filepath="$PROJECT_DIR$/.idea/modules/Another_Widget.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" group="Another Widget/app" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/app/Another_Widget.app.iml" filepath="$PROJECT_DIR$/.idea/modules/app/Another_Widget.app.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
@ -23,8 +23,8 @@ android {
|
|||||||
applicationId "com.tommasoberlose.anotherwidget"
|
applicationId "com.tommasoberlose.anotherwidget"
|
||||||
minSdkVersion 23
|
minSdkVersion 23
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 106
|
versionCode 108
|
||||||
versionName "2.0.14"
|
versionName "2.0.15"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
buildConfigField("String", "GOOGLE_API_KEY", apikeyProperties['GOOGLE_API_KEY'])
|
buildConfigField("String", "GOOGLE_API_KEY", apikeyProperties['GOOGLE_API_KEY'])
|
||||||
@ -64,13 +64,13 @@ dependencies {
|
|||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
testImplementation 'junit:junit:4.13'
|
testImplementation 'junit:junit:4.13.1'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.2'
|
||||||
implementation 'com.google.android.material:material:1.3.0-alpha03'
|
implementation 'com.google.android.material:material:1.3.0-alpha03'
|
||||||
implementation 'androidx.browser:browser:1.2.0'
|
implementation 'androidx.browser:browser:1.2.0'
|
||||||
implementation 'net.idik:slimadapter:2.1.2'
|
implementation 'net.idik:slimadapter:2.1.2'
|
||||||
@ -84,15 +84,15 @@ dependencies {
|
|||||||
implementation "androidx.work:work-runtime-ktx:2.4.0"
|
implementation "androidx.work:work-runtime-ktx:2.4.0"
|
||||||
|
|
||||||
// EventBus
|
// EventBus
|
||||||
implementation 'org.greenrobot:eventbus:3.1.1'
|
implementation 'org.greenrobot:eventbus:3.2.0'
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
implementation 'androidx.navigation:navigation-fragment:2.3.0'
|
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0'
|
||||||
implementation 'androidx.navigation:navigation-ui-ktx:2.3.0'
|
implementation 'androidx.navigation:navigation-ui-ktx:2.3.0'
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
implementation 'joda-time:joda-time:2.10.3'
|
implementation 'joda-time:joda-time:2.10.6'
|
||||||
implementation 'me.everything:providers-android:1.0.1'
|
implementation 'me.everything:providers-android:1.0.1'
|
||||||
implementation 'com.github.warkiz.widget:indicatorseekbar:2.1.2'
|
implementation 'com.github.warkiz.widget:indicatorseekbar:2.1.2'
|
||||||
|
|
||||||
@ -121,8 +121,8 @@ dependencies {
|
|||||||
//Retrofit
|
//Retrofit
|
||||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||||
implementation 'com.google.code.gson:gson:2.8.6'
|
implementation 'com.google.code.gson:gson:2.8.6'
|
||||||
implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
|
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
|
||||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.0'
|
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0'
|
||||||
implementation "com.github.haroldadmin:NetworkResponseAdapter:4.0.1"
|
implementation "com.github.haroldadmin:NetworkResponseAdapter:4.0.1"
|
||||||
|
|
||||||
//Coroutines
|
//Coroutines
|
||||||
@ -137,7 +137,7 @@ dependencies {
|
|||||||
implementation 'androidx.preference:preference-ktx:1.1.1'
|
implementation 'androidx.preference:preference-ktx:1.1.1'
|
||||||
|
|
||||||
// Permissions
|
// Permissions
|
||||||
implementation 'com.karumi:dexter:6.1.0'
|
implementation 'com.karumi:dexter:6.2.1'
|
||||||
|
|
||||||
// Fonts
|
// Fonts
|
||||||
implementation 'com.github.firatkarababa:downloadable-font-list-library:1.0.2'
|
implementation 'com.github.firatkarababa:downloadable-font-list-library:1.0.2'
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
<activity android:name=".ui.activities.CustomDateActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.CustomDateActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.IntegrationsActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.IntegrationsActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.MusicPlayersFilterActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.MusicPlayersFilterActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
|
<activity android:name=".ui.activities.AppNotificationsFilterActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
|
|
||||||
|
|
||||||
<receiver android:name=".ui.widgets.MainWidget">
|
<receiver android:name=".ui.widgets.MainWidget">
|
||||||
@ -120,7 +121,7 @@
|
|||||||
|
|
||||||
<service android:name=".services.BatteryListenerJob" android:permission="android.permission.BIND_JOB_SERVICE" />
|
<service android:name=".services.BatteryListenerJob" android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||||
|
|
||||||
<service android:name=".receivers.MusicNotificationListener"
|
<service android:name=".receivers.NotificationListener"
|
||||||
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
|
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.service.notification.NotificationListenerService" />
|
<action android:name="android.service.notification.NotificationListenerService" />
|
||||||
|
@ -6,13 +6,14 @@ import android.util.AttributeSet
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ScrollView
|
import android.widget.ScrollView
|
||||||
|
import androidx.core.widget.NestedScrollView
|
||||||
|
|
||||||
|
|
||||||
class FixedFocusScrollView @JvmOverloads constructor(
|
class FixedFocusScrollView @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
attrs: AttributeSet? = null,
|
attrs: AttributeSet? = null,
|
||||||
defStyle: Int = 0
|
defStyle: Int = 0
|
||||||
) : ScrollView(context, attrs, defStyle) {
|
) : NestedScrollView(context, attrs, defStyle) {
|
||||||
|
|
||||||
var isScrollable = true
|
var isScrollable = true
|
||||||
|
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
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(context)
|
|
||||||
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(context)
|
|
||||||
.mapNotNull { GlanceProviderHelper.getGlanceProviderById(context, it) }
|
|
||||||
)
|
|
||||||
|
|
||||||
setContentView(view)
|
|
||||||
super.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,329 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.components
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.AlarmManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import com.google.android.gms.auth.api.signin.GoogleSignIn
|
||||||
|
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
|
||||||
|
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
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.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.AppNotificationsFilterActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.MusicPlayersFilterActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
|
import kotlinx.android.synthetic.main.glance_provider_settings_layout.view.*
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
|
||||||
|
class GlanceSettingsDialog(val context: Activity, val provider: Constants.GlanceProviderId, private val statusCallback: (() -> Unit)?) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||||
|
|
||||||
|
override fun show() {
|
||||||
|
val view = View.inflate(context, R.layout.glance_provider_settings_layout, null)
|
||||||
|
|
||||||
|
/* TITLE */
|
||||||
|
view.title.text = when (provider) {
|
||||||
|
Constants.GlanceProviderId.PLAYING_SONG -> context.getString(R.string.settings_show_music_title)
|
||||||
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> context.getString(R.string.settings_show_next_alarm_title)
|
||||||
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> context.getString(R.string.settings_low_battery_level_title)
|
||||||
|
Constants.GlanceProviderId.CUSTOM_INFO -> context.getString(R.string.settings_custom_notes_title)
|
||||||
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> context.getString(R.string.settings_daily_steps_title)
|
||||||
|
Constants.GlanceProviderId.NOTIFICATIONS -> context.getString(R.string.settings_show_notifications_title)
|
||||||
|
Constants.GlanceProviderId.GREETINGS -> context.getString(R.string.settings_show_greetings_title)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SUBTITLE*/
|
||||||
|
view.subtitle.text = when (provider) {
|
||||||
|
Constants.GlanceProviderId.PLAYING_SONG -> context.getString(R.string.settings_show_music_subtitle)
|
||||||
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> context.getString(R.string.settings_show_next_alarm_subtitle)
|
||||||
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> context.getString(R.string.settings_low_battery_level_subtitle)
|
||||||
|
Constants.GlanceProviderId.CUSTOM_INFO -> ""
|
||||||
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> context.getString(R.string.settings_daily_steps_subtitle)
|
||||||
|
Constants.GlanceProviderId.NOTIFICATIONS -> context.getString(R.string.settings_show_notifications_subtitle)
|
||||||
|
Constants.GlanceProviderId.GREETINGS -> context.getString(R.string.settings_show_greetings_subtitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SONG */
|
||||||
|
view.action_filter_music_players.isVisible = provider == Constants.GlanceProviderId.PLAYING_SONG
|
||||||
|
if (provider == Constants.GlanceProviderId.PLAYING_SONG) {
|
||||||
|
view.action_filter_music_players.setOnClickListener {
|
||||||
|
context.startActivity(Intent(context, MusicPlayersFilterActivity::class.java))
|
||||||
|
}
|
||||||
|
checkNotificationPermission(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ALARM */
|
||||||
|
view.alarm_set_by_container.isVisible = provider == Constants.GlanceProviderId.NEXT_CLOCK_ALARM
|
||||||
|
if (provider == Constants.GlanceProviderId.NEXT_CLOCK_ALARM) {
|
||||||
|
view.header.text = context.getString(R.string.information_header)
|
||||||
|
view.warning_container.isVisible = false
|
||||||
|
checkNextAlarm(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GOOGLE STEPS */
|
||||||
|
view.action_toggle_google_fit.isVisible = provider == Constants.GlanceProviderId.GOOGLE_FIT_STEPS
|
||||||
|
if (provider == Constants.GlanceProviderId.GOOGLE_FIT_STEPS) {
|
||||||
|
view.warning_container.isVisible = false
|
||||||
|
checkFitnessPermission(view)
|
||||||
|
checkGoogleFitConnection(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BATTERY INFO */
|
||||||
|
if (provider == Constants.GlanceProviderId.BATTERY_LEVEL_LOW) {
|
||||||
|
view.warning_container.isVisible = false
|
||||||
|
view.header.isVisible = false
|
||||||
|
view.divider.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTIFICATIONS */
|
||||||
|
view.action_filter_notifications_app.isVisible = provider == Constants.GlanceProviderId.NOTIFICATIONS
|
||||||
|
if (provider == Constants.GlanceProviderId.NOTIFICATIONS) {
|
||||||
|
checkLastNotificationsPermission(view)
|
||||||
|
view.action_filter_notifications_app.setOnClickListener {
|
||||||
|
context.startActivity(Intent(context, AppNotificationsFilterActivity::class.java))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GREETINGS */
|
||||||
|
if (provider == Constants.GlanceProviderId.GREETINGS) {
|
||||||
|
view.warning_container.isVisible = false
|
||||||
|
view.header.isVisible = false
|
||||||
|
view.divider.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TOGGLE */
|
||||||
|
view.provider_switch.isChecked = when (provider) {
|
||||||
|
Constants.GlanceProviderId.PLAYING_SONG -> Preferences.showMusic
|
||||||
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> Preferences.showNextAlarm
|
||||||
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> Preferences.showBatteryCharging
|
||||||
|
Constants.GlanceProviderId.CUSTOM_INFO -> true
|
||||||
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> Preferences.showDailySteps
|
||||||
|
Constants.GlanceProviderId.NOTIFICATIONS -> Preferences.showNotifications
|
||||||
|
Constants.GlanceProviderId.GREETINGS -> Preferences.showGreetings
|
||||||
|
}
|
||||||
|
|
||||||
|
var job: Job? = null
|
||||||
|
|
||||||
|
view.provider_switch.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
job?.cancel()
|
||||||
|
job = GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
delay(300)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
when (provider) {
|
||||||
|
Constants.GlanceProviderId.PLAYING_SONG -> {
|
||||||
|
Preferences.showMusic = isChecked
|
||||||
|
checkNotificationPermission(view)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||||
|
Preferences.showNextAlarm = isChecked
|
||||||
|
checkNextAlarm(view)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||||
|
Preferences.showBatteryCharging = isChecked
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.NOTIFICATIONS -> {
|
||||||
|
Preferences.showNotifications = isChecked
|
||||||
|
checkLastNotificationsPermission(view)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.GREETINGS -> {
|
||||||
|
Preferences.showGreetings = isChecked
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
||||||
|
if (isChecked) {
|
||||||
|
val account: GoogleSignInAccount? =
|
||||||
|
GoogleSignIn.getLastSignedInAccount(context)
|
||||||
|
if (!GoogleSignIn.hasPermissions(account,
|
||||||
|
ActivityDetectionReceiver.FITNESS_OPTIONS
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
val mGoogleSignInClient =
|
||||||
|
GoogleSignIn.getClient(context, GoogleSignInOptions.Builder(
|
||||||
|
GoogleSignInOptions.DEFAULT_SIGN_IN).addExtension(
|
||||||
|
ActivityDetectionReceiver.FITNESS_OPTIONS
|
||||||
|
).build())
|
||||||
|
context.startActivityForResult(mGoogleSignInClient.signInIntent,
|
||||||
|
2)
|
||||||
|
} else {
|
||||||
|
Preferences.showDailySteps = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Preferences.showDailySteps = false
|
||||||
|
}
|
||||||
|
|
||||||
|
view.warning_container.isVisible = false
|
||||||
|
checkFitnessPermission(view)
|
||||||
|
checkGoogleFitConnection(view)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statusCallback?.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setContentView(view)
|
||||||
|
super.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkNextAlarm(view: View) {
|
||||||
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
|
val alarm = nextAlarmClock
|
||||||
|
if (alarm != null && alarm.showIntent != null) {
|
||||||
|
val pm = context.packageManager as PackageManager
|
||||||
|
val appNameOrPackage = try {
|
||||||
|
pm.getApplicationLabel(pm.getApplicationInfo(alarm.showIntent?.creatorPackage ?: "", 0))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
alarm.showIntent?.creatorPackage ?: ""
|
||||||
|
}
|
||||||
|
view.alarm_set_by_title.text = context.getString(R.string.settings_show_next_alarm_app_title).format(appNameOrPackage)
|
||||||
|
view.alarm_set_by_subtitle.text = if (AlarmHelper.isAlarmProbablyWrong(context)) context.getString(R.string.settings_show_next_alarm_app_subtitle_wrong) else context.getString(R.string.settings_show_next_alarm_app_subtitle_correct)
|
||||||
|
view.alarm_set_by_title.isVisible = true
|
||||||
|
} else {
|
||||||
|
view.alarm_set_by_title.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statusCallback?.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkNotificationPermission(view: View) {
|
||||||
|
when {
|
||||||
|
ActiveNotificationsHelper.checkNotificationAccess(context) -> {
|
||||||
|
view.warning_container.isVisible = false
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(context)
|
||||||
|
}
|
||||||
|
Preferences.showMusic -> {
|
||||||
|
view.warning_container.isVisible = true
|
||||||
|
view.warning_title.text = context.getString(R.string.settings_request_notification_access)
|
||||||
|
view.warning_container.setOnClickListener {
|
||||||
|
context.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
view.warning_container.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statusCallback?.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkLastNotificationsPermission(view: View) {
|
||||||
|
when {
|
||||||
|
ActiveNotificationsHelper.checkNotificationAccess(context) -> {
|
||||||
|
view.warning_container.isVisible = false
|
||||||
|
}
|
||||||
|
Preferences.showNotifications -> {
|
||||||
|
view.warning_container.isVisible = true
|
||||||
|
view.warning_title.text = context.getString(R.string.settings_request_last_notification_access)
|
||||||
|
view.warning_container.setOnClickListener {
|
||||||
|
context.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
view.warning_container.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statusCallback?.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkFitnessPermission(view: View) {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(
|
||||||
|
Manifest.permission.ACTIVITY_RECOGNITION)
|
||||||
|
) {
|
||||||
|
if (Preferences.showDailySteps) {
|
||||||
|
ActivityDetectionReceiver.registerFence(context)
|
||||||
|
} else {
|
||||||
|
ActivityDetectionReceiver.unregisterFence(context)
|
||||||
|
}
|
||||||
|
} else if (Preferences.showDailySteps) {
|
||||||
|
ActivityDetectionReceiver.unregisterFence(context)
|
||||||
|
view.warning_container.isVisible = true
|
||||||
|
view.warning_title.text = context.getString(R.string.settings_request_fitness_access)
|
||||||
|
view.warning_container.setOnClickListener {
|
||||||
|
requireFitnessPermission(view)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ActivityDetectionReceiver.unregisterFence(context)
|
||||||
|
}
|
||||||
|
statusCallback?.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkGoogleFitConnection(view: View) {
|
||||||
|
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(context)
|
||||||
|
if (!GoogleSignIn.hasPermissions(account,
|
||||||
|
ActivityDetectionReceiver.FITNESS_OPTIONS
|
||||||
|
)) {
|
||||||
|
view.warning_container.isVisible = true
|
||||||
|
view.warning_title.text = context.getString(R.string.settings_request_fitness_access)
|
||||||
|
view.warning_container.setOnClickListener {
|
||||||
|
GoogleSignIn.requestPermissions(
|
||||||
|
context,
|
||||||
|
1,
|
||||||
|
account,
|
||||||
|
ActivityDetectionReceiver.FITNESS_OPTIONS)
|
||||||
|
}
|
||||||
|
view.action_connect_to_google_fit.isVisible = true
|
||||||
|
view.action_disconnect_to_google_fit.isVisible = false
|
||||||
|
view.action_connect_to_google_fit.setOnClickListener {
|
||||||
|
GoogleSignIn.requestPermissions(
|
||||||
|
context,
|
||||||
|
1,
|
||||||
|
account,
|
||||||
|
ActivityDetectionReceiver.FITNESS_OPTIONS)
|
||||||
|
}
|
||||||
|
view.action_disconnect_to_google_fit.setOnClickListener(null)
|
||||||
|
view.google_fit_status_label.text = context.getString(R.string.google_fit_account_not_connected)
|
||||||
|
} else {
|
||||||
|
view.action_connect_to_google_fit.isVisible = false
|
||||||
|
view.action_disconnect_to_google_fit.isVisible = true
|
||||||
|
view.action_connect_to_google_fit.setOnClickListener(null)
|
||||||
|
view.action_disconnect_to_google_fit.setOnClickListener {
|
||||||
|
GoogleSignIn.getClient(context, GoogleSignInOptions.Builder(
|
||||||
|
GoogleSignInOptions.DEFAULT_SIGN_IN).addExtension(
|
||||||
|
ActivityDetectionReceiver.FITNESS_OPTIONS
|
||||||
|
).build()).signOut().addOnCompleteListener {
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
view.google_fit_status_label.text = context.getString(R.string.google_fit_account_connected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun requireFitnessPermission(view: View) {
|
||||||
|
Dexter.withContext(context)
|
||||||
|
.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?) {
|
||||||
|
checkFitnessPermission(view)
|
||||||
|
}
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
@ -5,10 +5,12 @@ object Actions {
|
|||||||
const val ACTION_EXTRA_DISABLE_GPS_NOTIFICATION = "ACTION_EXTRA_DISABLE_GPS_NOTIFICATION"
|
const val ACTION_EXTRA_DISABLE_GPS_NOTIFICATION = "ACTION_EXTRA_DISABLE_GPS_NOTIFICATION"
|
||||||
|
|
||||||
const val ACTION_TIME_UPDATE = "com.tommasoberlose.anotherwidget.action.TIME_UPDATE"
|
const val ACTION_TIME_UPDATE = "com.tommasoberlose.anotherwidget.action.TIME_UPDATE"
|
||||||
|
const val ACTION_ALARM_UPDATE = "com.tommasoberlose.anotherwidget.action.ALARM_UPDATE"
|
||||||
const val ACTION_CALENDAR_UPDATE = "com.tommasoberlose.anotherwidget.action.CALENDAR_UPDATE"
|
const val ACTION_CALENDAR_UPDATE = "com.tommasoberlose.anotherwidget.action.CALENDAR_UPDATE"
|
||||||
const val ACTION_WEATHER_UPDATE = "com.tommasoberlose.anotherwidget.action.WEATHER_UPDATE"
|
const val ACTION_WEATHER_UPDATE = "com.tommasoberlose.anotherwidget.action.WEATHER_UPDATE"
|
||||||
const val ACTION_OPEN_WEATHER_INTENT = "com.tommasoberlose.anotherwidget.action.OPEN_WEATHER_INTENT"
|
const val ACTION_OPEN_WEATHER_INTENT = "com.tommasoberlose.anotherwidget.action.OPEN_WEATHER_INTENT"
|
||||||
const val ACTION_GO_TO_NEXT_EVENT = "com.tommasoberlose.anotherwidget.action.GO_TO_NEXT_EVENT"
|
const val ACTION_GO_TO_NEXT_EVENT = "com.tommasoberlose.anotherwidget.action.GO_TO_NEXT_EVENT"
|
||||||
const val ACTION_GO_TO_PREVIOUS_EVENT = "com.tommasoberlose.anotherwidget.action.GO_TO_PREVIOUS_EVENT"
|
const val ACTION_GO_TO_PREVIOUS_EVENT = "com.tommasoberlose.anotherwidget.action.GO_TO_PREVIOUS_EVENT"
|
||||||
const val ACTION_REPORT_CRASH = "com.tommasoberlose.anotherwidget.action.REPORT_CRASH"
|
const val ACTION_REPORT_CRASH = "com.tommasoberlose.anotherwidget.action.REPORT_CRASH"
|
||||||
|
const val ACTION_CLEAR_NOTIFICATION = "com.tommasoberlose.anotherwidget.action.CLEAR_NOTIFICATION"
|
||||||
}
|
}
|
@ -30,7 +30,14 @@ object Constants {
|
|||||||
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"),
|
||||||
|
NOTIFICATIONS("NOTIFICATIONS"),
|
||||||
|
GREETINGS("GREETINGS");
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val map = GlanceProviderId.values().associateBy(GlanceProviderId::id)
|
||||||
|
fun from(type: String) = map[type]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class WidgetUpdateFrequency(val value: Int) {
|
enum class WidgetUpdateFrequency(val value: Int) {
|
||||||
|
@ -123,6 +123,13 @@ object Preferences : KotprefModel() {
|
|||||||
var isCharging by booleanPref(default = false)
|
var isCharging by booleanPref(default = false)
|
||||||
var googleFitSteps by longPref(default = -1)
|
var googleFitSteps by longPref(default = -1)
|
||||||
var showDailySteps by booleanPref(default = false)
|
var showDailySteps by booleanPref(default = false)
|
||||||
|
var showGreetings by booleanPref(default = false)
|
||||||
|
var showNotifications by booleanPref(default = false)
|
||||||
|
|
||||||
|
var lastNotificationId by intPref(default = -1)
|
||||||
|
var lastNotificationTitle by stringPref(default = "")
|
||||||
|
var lastNotificationIcon by intPref(default = 0)
|
||||||
|
var lastNotificationPackage by stringPref(default = "")
|
||||||
|
|
||||||
var showMusic by booleanPref(default = false)
|
var showMusic by booleanPref(default = false)
|
||||||
var mediaInfoFormat by stringPref(default = "")
|
var mediaInfoFormat by stringPref(default = "")
|
||||||
@ -131,6 +138,7 @@ object Preferences : KotprefModel() {
|
|||||||
var mediaPlayerArtist by stringPref(default = "")
|
var mediaPlayerArtist by stringPref(default = "")
|
||||||
var mediaPlayerPackage by stringPref(default = "")
|
var mediaPlayerPackage by stringPref(default = "")
|
||||||
var musicPlayersFilter by stringPref(default = "")
|
var musicPlayersFilter by stringPref(default = "")
|
||||||
|
var appNotificationsFilter by stringPref(default = "")
|
||||||
|
|
||||||
// Integrations
|
// Integrations
|
||||||
var installedIntegrations by intPref(default = 0)
|
var installedIntegrations by intPref(default = 0)
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
|
import android.content.ContentResolver
|
||||||
|
import android.content.Context
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import com.chibatching.kotpref.Kotpref
|
||||||
|
import com.chibatching.kotpref.blockingBulk
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.NotificationListener
|
||||||
|
|
||||||
|
object ActiveNotificationsHelper {
|
||||||
|
fun showLastNotification(): Boolean {
|
||||||
|
return Preferences.lastNotificationId != -1 && Preferences.lastNotificationIcon != 0 && Preferences.lastNotificationPackage.isNotBlank() && Preferences.lastNotificationTitle.isNotBlank()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearLastNotification(context: Context) {
|
||||||
|
Kotpref.init(context)
|
||||||
|
Preferences.blockingBulk {
|
||||||
|
remove(Preferences::lastNotificationId)
|
||||||
|
remove(Preferences::lastNotificationTitle)
|
||||||
|
remove(Preferences::lastNotificationPackage)
|
||||||
|
remove(Preferences::lastNotificationIcon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkNotificationAccess(context: Context): Boolean {
|
||||||
|
val contentResolver: ContentResolver = context.contentResolver
|
||||||
|
val enabledNotificationListeners =
|
||||||
|
Settings.Secure.getString(contentResolver, "enabled_notification_listeners")
|
||||||
|
val packageName: String = context.packageName
|
||||||
|
return NotificationManagerCompat.getEnabledListenerPackages(context).contains(packageName) && (enabledNotificationListeners != null && enabledNotificationListeners.contains(NotificationListener::class.java.name))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAppAccepted(appPkg: String): Boolean = Preferences.appNotificationsFilter == "" || Preferences.appNotificationsFilter.contains(appPkg)
|
||||||
|
|
||||||
|
fun toggleAppFilter(appPkg: String) {
|
||||||
|
if (Preferences.appNotificationsFilter == "" || !Preferences.appNotificationsFilter.contains(appPkg)) {
|
||||||
|
Preferences.appNotificationsFilter = Preferences.appNotificationsFilter.split(",").union(listOf(appPkg)).joinToString(separator = ",")
|
||||||
|
} else {
|
||||||
|
Preferences.appNotificationsFilter = Preferences.appNotificationsFilter.split(",").filter { it != appPkg }.joinToString(separator = ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,14 @@
|
|||||||
package com.tommasoberlose.anotherwidget.helpers
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
import android.app.AlarmManager
|
import android.app.AlarmManager
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.text.format.DateFormat
|
import android.text.format.DateFormat
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -14,6 +19,7 @@ object AlarmHelper {
|
|||||||
alarm != null
|
alarm != null
|
||||||
&& alarm.triggerTime - Calendar.getInstance().timeInMillis > 5 * 60 * 1000
|
&& alarm.triggerTime - Calendar.getInstance().timeInMillis > 5 * 60 * 1000
|
||||||
) {
|
) {
|
||||||
|
setTimeout(context, alarm.triggerTime)
|
||||||
"%s %s".format(
|
"%s %s".format(
|
||||||
SimpleDateFormat("EEE", Locale.getDefault()).format(alarm.triggerTime),
|
SimpleDateFormat("EEE", Locale.getDefault()).format(alarm.triggerTime),
|
||||||
DateFormat.getTimeFormat(context).format(Date(alarm.triggerTime))
|
DateFormat.getTimeFormat(context).format(Date(alarm.triggerTime))
|
||||||
@ -32,4 +38,25 @@ object AlarmHelper {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setTimeout(context: Context, trigger: Long) {
|
||||||
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
|
val intent = Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_ALARM_UPDATE
|
||||||
|
}
|
||||||
|
cancel(PendingIntent.getBroadcast(context, ALARM_UPDATE_ID, intent, 0))
|
||||||
|
setExact(
|
||||||
|
AlarmManager.RTC,
|
||||||
|
trigger,
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
ALARM_UPDATE_ID,
|
||||||
|
intent,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val ALARM_UPDATE_ID = 24953
|
||||||
}
|
}
|
@ -1,7 +1,6 @@
|
|||||||
package com.tommasoberlose.anotherwidget.helpers
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.db.EventRepository
|
import com.tommasoberlose.anotherwidget.db.EventRepository
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
@ -44,19 +43,19 @@ 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_access_alarm
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
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_radio
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
||||||
GlanceProvider(providerId.id,
|
GlanceProvider(providerId.id,
|
||||||
context.getString(R.string.settings_custom_notes_title),
|
context.getString(R.string.settings_custom_notes_title),
|
||||||
R.drawable.round_notes
|
R.drawable.round_sticky_note_2
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||||
@ -68,7 +67,19 @@ object GlanceProviderHelper {
|
|||||||
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
||||||
GlanceProvider(providerId.id,
|
GlanceProvider(providerId.id,
|
||||||
context.getString(R.string.settings_daily_steps_title),
|
context.getString(R.string.settings_daily_steps_title),
|
||||||
R.drawable.round_directions_walk
|
R.drawable.round_run_circle
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.NOTIFICATIONS -> {
|
||||||
|
GlanceProvider(providerId.id,
|
||||||
|
context.getString(R.string.settings_show_notifications_title),
|
||||||
|
R.drawable.round_notifications
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.GREETINGS -> {
|
||||||
|
GlanceProvider(providerId.id,
|
||||||
|
context.getString(R.string.settings_show_greetings_title),
|
||||||
|
R.drawable.round_history_edu
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,7 +93,9 @@ object GlanceProviderHelper {
|
|||||||
val eventRepository = EventRepository(context)
|
val eventRepository = EventRepository(context)
|
||||||
BatteryHelper.updateBatteryInfo(context)
|
BatteryHelper.updateBatteryInfo(context)
|
||||||
|
|
||||||
val showGlance = Preferences.showGlance && (eventRepository.getEventsCount() == 0 || !Preferences.showEvents) && (
|
val showGlance = Preferences.showGlance && (eventRepository.getEventsCount() == 0 || !Preferences.showEvents)
|
||||||
|
&& (
|
||||||
|
(Preferences.showNotifications && ActiveNotificationsHelper.showLastNotification()) ||
|
||||||
(Preferences.showNextAlarm && AlarmHelper.getNextAlarm(context) != "") ||
|
(Preferences.showNextAlarm && AlarmHelper.getNextAlarm(context) != "") ||
|
||||||
(MediaPlayerHelper.isSomeonePlaying(context)) ||
|
(MediaPlayerHelper.isSomeonePlaying(context)) ||
|
||||||
(Preferences.showBatteryCharging && Preferences.isCharging || Preferences.isBatteryLevelLow) ||
|
(Preferences.showBatteryCharging && Preferences.isCharging || Preferences.isBatteryLevelLow) ||
|
||||||
|
@ -222,4 +222,16 @@ object IntentHelper {
|
|||||||
Intent()
|
Intent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getNotificationIntent(context: Context): Intent {
|
||||||
|
val pm: PackageManager = context.packageManager
|
||||||
|
return try {
|
||||||
|
pm.getLaunchIntentForPackage(Preferences.lastNotificationPackage)!!.apply {
|
||||||
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
context.toast(context.getString(R.string.error_opening_app))
|
||||||
|
Intent()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,25 +1,21 @@
|
|||||||
package com.tommasoberlose.anotherwidget.helpers
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
import android.app.Notification
|
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.media.MediaMetadata
|
import android.media.MediaMetadata
|
||||||
import android.media.session.MediaController
|
import android.media.session.MediaController
|
||||||
import android.media.session.MediaSession
|
|
||||||
import android.media.session.MediaSessionManager
|
import android.media.session.MediaSessionManager
|
||||||
import android.media.session.PlaybackState
|
import android.media.session.PlaybackState
|
||||||
import android.util.Log
|
|
||||||
import androidx.core.app.NotificationManagerCompat
|
|
||||||
import com.chibatching.kotpref.Kotpref
|
import com.chibatching.kotpref.Kotpref
|
||||||
import com.chibatching.kotpref.blockingBulk
|
import com.chibatching.kotpref.blockingBulk
|
||||||
import com.chibatching.kotpref.bulk
|
import com.chibatching.kotpref.bulk
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.receivers.MusicNotificationListener
|
import com.tommasoberlose.anotherwidget.receivers.NotificationListener
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
|
|
||||||
object MediaPlayerHelper {
|
object MediaPlayerHelper {
|
||||||
fun isSomeonePlaying(context: Context) = Preferences.showMusic && NotificationManagerCompat.getEnabledListenerPackages(context).contains(context.packageName) && Preferences.mediaPlayerTitle != ""
|
fun isSomeonePlaying(context: Context) = Preferences.showMusic && ActiveNotificationsHelper.checkNotificationAccess(context) && Preferences.mediaPlayerTitle != ""
|
||||||
|
|
||||||
fun getMediaInfo(): String {
|
fun getMediaInfo(): String {
|
||||||
return if (Preferences.mediaPlayerArtist == "") {
|
return if (Preferences.mediaPlayerArtist == "") {
|
||||||
@ -31,10 +27,10 @@ object MediaPlayerHelper {
|
|||||||
|
|
||||||
fun updatePlayingMediaInfo(context: Context) {
|
fun updatePlayingMediaInfo(context: Context) {
|
||||||
Kotpref.init(context)
|
Kotpref.init(context)
|
||||||
if (NotificationManagerCompat.getEnabledListenerPackages(context).contains(context.packageName)) {
|
if (ActiveNotificationsHelper.checkNotificationAccess(context)) {
|
||||||
val list = try {
|
val list = try {
|
||||||
(context.getSystemService(Context.MEDIA_SESSION_SERVICE) as MediaSessionManager).getActiveSessions(
|
(context.getSystemService(Context.MEDIA_SESSION_SERVICE) as MediaSessionManager).getActiveSessions(
|
||||||
ComponentName(context.packageName, MusicNotificationListener::class.java.name)
|
ComponentName(context.packageName, NotificationListener::class.java.name)
|
||||||
)
|
)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
emptyList<MediaController>()
|
emptyList<MediaController>()
|
||||||
@ -92,7 +88,7 @@ object MediaPlayerHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isMusicPlayerAccepted(appPkg: String): Boolean = Preferences.musicPlayersFilter.contains(appPkg)
|
fun isMusicPlayerAccepted(appPkg: String): Boolean = Preferences.musicPlayersFilter == "" || Preferences.musicPlayersFilter.contains(appPkg)
|
||||||
|
|
||||||
fun toggleMusicPlayerFilter(appPkg: String) {
|
fun toggleMusicPlayerFilter(appPkg: String) {
|
||||||
if (Preferences.musicPlayersFilter == "" || !Preferences.musicPlayersFilter.contains(appPkg)) {
|
if (Preferences.musicPlayersFilter == "" || !Preferences.musicPlayersFilter.contains(appPkg)) {
|
||||||
|
@ -4,6 +4,7 @@ import android.Manifest
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import com.chibatching.kotpref.Kotpref
|
||||||
import com.google.android.gms.location.LocationServices
|
import com.google.android.gms.location.LocationServices
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
@ -26,6 +27,7 @@ import org.greenrobot.eventbus.EventBus
|
|||||||
object WeatherHelper {
|
object WeatherHelper {
|
||||||
|
|
||||||
suspend fun updateWeather(context: Context) {
|
suspend fun updateWeather(context: Context) {
|
||||||
|
Kotpref.init(context)
|
||||||
val networkApi = WeatherNetworkApi(context)
|
val networkApi = WeatherNetworkApi(context)
|
||||||
if (Preferences.customLocationAdd != "") {
|
if (Preferences.customLocationAdd != "") {
|
||||||
networkApi.updateWeather()
|
networkApi.updateWeather()
|
||||||
|
@ -167,7 +167,7 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
|
|||||||
private fun setTimeout(context: Context) {
|
private fun setTimeout(context: Context) {
|
||||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
cancel(PendingIntent.getBroadcast(context, 5, Intent(context, ActivityDetectionReceiver::class.java), 0))
|
cancel(PendingIntent.getBroadcast(context, 5, Intent(context, ActivityDetectionReceiver::class.java), 0))
|
||||||
setExactAndAllowWhileIdle(
|
setExact(
|
||||||
AlarmManager.RTC,
|
AlarmManager.RTC,
|
||||||
Calendar.getInstance().timeInMillis + 5 * 60 * 1000,
|
Calendar.getInstance().timeInMillis + 5 * 60 * 1000,
|
||||||
PendingIntent.getBroadcast(
|
PendingIntent.getBroadcast(
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.receivers
|
|
||||||
|
|
||||||
import android.app.Notification
|
|
||||||
import android.media.MediaMetadata
|
|
||||||
import android.media.session.MediaController
|
|
||||||
import android.media.session.MediaSession
|
|
||||||
import android.media.session.PlaybackState
|
|
||||||
import android.service.notification.NotificationListenerService
|
|
||||||
import android.service.notification.StatusBarNotification
|
|
||||||
import android.util.Log
|
|
||||||
import com.chibatching.kotpref.bulk
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.WidgetHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
|
||||||
|
|
||||||
|
|
||||||
class MusicNotificationListener : NotificationListenerService() {
|
|
||||||
override fun onListenerConnected() {
|
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
|
||||||
super.onListenerConnected()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNotificationPosted(sbn: StatusBarNotification?) {
|
|
||||||
sbn?.notification?.extras?.let { bundle ->
|
|
||||||
bundle.getParcelable<MediaSession.Token>(Notification.EXTRA_MEDIA_SESSION)?.let {
|
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.onNotificationPosted(sbn)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNotificationRemoved(sbn: StatusBarNotification?) {
|
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
|
||||||
super.onNotificationRemoved(sbn)
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,84 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.receivers
|
||||||
|
|
||||||
|
import android.app.*
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.media.session.MediaSession
|
||||||
|
import android.os.Build
|
||||||
|
import android.service.notification.NotificationListenerService
|
||||||
|
import android.service.notification.StatusBarNotification
|
||||||
|
import android.util.Log
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
class NotificationListener : NotificationListenerService() {
|
||||||
|
override fun onListenerConnected() {
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
||||||
|
MainWidget.updateWidget(this)
|
||||||
|
super.onListenerConnected()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNotificationPosted(sbn: StatusBarNotification?) {
|
||||||
|
sbn?.notification?.extras?.let { bundle ->
|
||||||
|
bundle.getParcelable<MediaSession.Token>(Notification.EXTRA_MEDIA_SESSION)?.let {
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
||||||
|
} ?: run {
|
||||||
|
val isGroupHeader = sbn.notification.flags and Notification.FLAG_GROUP_SUMMARY != 0
|
||||||
|
val isOngoing = sbn.notification.flags and Notification.FLAG_ONGOING_EVENT != 0
|
||||||
|
|
||||||
|
if (bundle.containsKey(Notification.EXTRA_TITLE) && !isGroupHeader && !isOngoing && ActiveNotificationsHelper.isAppAccepted(sbn.packageName)) {
|
||||||
|
Preferences.lastNotificationId = sbn.id
|
||||||
|
Preferences.lastNotificationTitle = bundle.getString(Notification.EXTRA_TITLE) ?: ""
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
Preferences.lastNotificationIcon = sbn.notification.smallIcon.resId
|
||||||
|
Preferences.lastNotificationPackage = sbn.notification.smallIcon.resPackage
|
||||||
|
} else {
|
||||||
|
Preferences.lastNotificationIcon = sbn.notification.icon
|
||||||
|
Preferences.lastNotificationPackage = sbn.packageName
|
||||||
|
}
|
||||||
|
MainWidget.updateWidget(this)
|
||||||
|
setTimeout(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onNotificationPosted(sbn)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNotificationRemoved(sbn: StatusBarNotification?) {
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
||||||
|
|
||||||
|
sbn?.let {
|
||||||
|
if (sbn.id == Preferences.lastNotificationId && sbn.packageName == Preferences.lastNotificationPackage) {
|
||||||
|
ActiveNotificationsHelper.clearLastNotification(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWidget.updateWidget(this)
|
||||||
|
super.onNotificationRemoved(sbn)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setTimeout(context: Context) {
|
||||||
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
|
val intent = Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_CLEAR_NOTIFICATION
|
||||||
|
}
|
||||||
|
cancel(PendingIntent.getBroadcast(context, 28943, intent, 0))
|
||||||
|
setExact(
|
||||||
|
AlarmManager.RTC,
|
||||||
|
Calendar.getInstance().timeInMillis + 30 * 1000,
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
5,
|
||||||
|
intent,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,8 +12,10 @@ import com.tommasoberlose.anotherwidget.db.EventRepository
|
|||||||
import com.tommasoberlose.anotherwidget.global.Actions
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
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.helpers.ActiveNotificationsHelper
|
||||||
import com.tommasoberlose.anotherwidget.helpers.BatteryHelper
|
import com.tommasoberlose.anotherwidget.helpers.BatteryHelper
|
||||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
import com.tommasoberlose.anotherwidget.models.Event
|
import com.tommasoberlose.anotherwidget.models.Event
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
import org.joda.time.Period
|
import org.joda.time.Period
|
||||||
@ -32,16 +34,24 @@ class UpdatesReceiver : BroadcastReceiver() {
|
|||||||
Intent.ACTION_DATE_CHANGED,
|
Intent.ACTION_DATE_CHANGED,
|
||||||
Actions.ACTION_CALENDAR_UPDATE -> {
|
Actions.ACTION_CALENDAR_UPDATE -> {
|
||||||
CalendarHelper.updateEventList(context)
|
CalendarHelper.updateEventList(context)
|
||||||
|
ActiveNotificationsHelper.clearLastNotification(context)
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
"com.sec.android.widgetapp.APPWIDGET_RESIZE",
|
"com.sec.android.widgetapp.APPWIDGET_RESIZE",
|
||||||
AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED,
|
AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED,
|
||||||
|
Actions.ACTION_ALARM_UPDATE,
|
||||||
Actions.ACTION_TIME_UPDATE -> {
|
Actions.ACTION_TIME_UPDATE -> {
|
||||||
MainWidget.updateWidget(context)
|
MainWidget.updateWidget(context)
|
||||||
if (intent.hasExtra(EVENT_ID)) {
|
if (intent.hasExtra(EVENT_ID)) {
|
||||||
setUpdates(context, intent.getLongExtra(EVENT_ID, -1))
|
setUpdates(context, intent.getLongExtra(EVENT_ID, -1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Actions.ACTION_CLEAR_NOTIFICATION -> {
|
||||||
|
ActiveNotificationsHelper.clearLastNotification(context)
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,143 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.activities
|
||||||
|
|
||||||
|
import android.content.pm.ResolveInfo
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.ActivityAppNotificationsFilterBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.AppNotificationsViewModel
|
||||||
|
import kotlinx.android.synthetic.main.activity_app_notifications_filter.*
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
|
||||||
|
|
||||||
|
class AppNotificationsFilterActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
|
private lateinit var viewModel: AppNotificationsViewModel
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(this).get(AppNotificationsViewModel::class.java)
|
||||||
|
val binding = DataBindingUtil.setContentView<ActivityAppNotificationsFilterBinding>(this, R.layout.activity_app_notifications_filter)
|
||||||
|
|
||||||
|
list_view.setHasFixedSize(true)
|
||||||
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
|
list_view.layoutManager = mLayoutManager
|
||||||
|
|
||||||
|
adapter = SlimAdapter.create()
|
||||||
|
adapter
|
||||||
|
.register<ResolveInfo>(R.layout.application_info_layout) { item, injector ->
|
||||||
|
injector
|
||||||
|
.text(R.id.text, item.loadLabel(viewModel.pm))
|
||||||
|
.with<ImageView>(R.id.icon) {
|
||||||
|
Glide
|
||||||
|
.with(this)
|
||||||
|
.load(item.loadIcon(viewModel.pm))
|
||||||
|
.centerCrop()
|
||||||
|
.into(it)
|
||||||
|
}
|
||||||
|
.visible(R.id.checkBox)
|
||||||
|
.clicked(R.id.item) {
|
||||||
|
toggleApp(item)
|
||||||
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
|
}
|
||||||
|
.clicked(R.id.checkBox) {
|
||||||
|
toggleApp(item)
|
||||||
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
|
}
|
||||||
|
.checked(R.id.checkBox, ActiveNotificationsHelper.isAppAccepted(item.activityInfo.packageName))
|
||||||
|
}
|
||||||
|
.attachTo(list_view)
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
|
search.requestFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
private var filterJob: Job? = null
|
||||||
|
|
||||||
|
private fun subscribeUi(binding: ActivityAppNotificationsFilterBinding, viewModel: AppNotificationsViewModel) {
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
|
||||||
|
viewModel.appList.observe(this, Observer {
|
||||||
|
updateList(list = it)
|
||||||
|
loader.visibility = View.INVISIBLE
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.searchInput.observe(this, Observer { search ->
|
||||||
|
updateList(search = search)
|
||||||
|
clear_search.isVisible = search.isNotBlank()
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.appNotificationsFilter.observe(this, {
|
||||||
|
updateList()
|
||||||
|
clear_selection.isVisible = Preferences.appNotificationsFilter != ""
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateList(list: List<ResolveInfo>? = viewModel.appList.value, search: String? = viewModel.searchInput.value) {
|
||||||
|
loader.visibility = View.VISIBLE
|
||||||
|
filterJob?.cancel()
|
||||||
|
filterJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
if (list != null && list.isNotEmpty()) {
|
||||||
|
delay(200)
|
||||||
|
val filteredList: List<ResolveInfo> = if (search == null || search == "") {
|
||||||
|
list
|
||||||
|
} else {
|
||||||
|
list.filter {
|
||||||
|
it.loadLabel(viewModel.pm).contains(search, true)
|
||||||
|
}
|
||||||
|
}.sortedWith { app1, app2 ->
|
||||||
|
if (ActiveNotificationsHelper.isAppAccepted(app1.activityInfo.packageName) && ActiveNotificationsHelper.isAppAccepted(app2.activityInfo.packageName)) {
|
||||||
|
app1.loadLabel(viewModel.pm).toString().compareTo(app2.loadLabel(viewModel.pm).toString(), ignoreCase = true)
|
||||||
|
} else if (ActiveNotificationsHelper.isAppAccepted(app1.activityInfo.packageName)) {
|
||||||
|
-1
|
||||||
|
} else if (ActiveNotificationsHelper.isAppAccepted(app2.activityInfo.packageName)) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
app1.loadLabel(viewModel.pm).toString().compareTo(app2.loadLabel(viewModel.pm).toString(), ignoreCase = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
adapter.updateData(filteredList)
|
||||||
|
loader.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
action_back.setOnClickListener {
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_search.setOnClickListener {
|
||||||
|
viewModel.searchInput.value = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_selection.setOnClickListener {
|
||||||
|
Preferences.appNotificationsFilter = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toggleApp(app: ResolveInfo) {
|
||||||
|
ActiveNotificationsHelper.toggleAppFilter(app.activityInfo.packageName)
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ import android.view.View
|
|||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
@ -21,7 +22,12 @@ import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBin
|
|||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.*
|
import kotlinx.android.synthetic.main.activity_choose_application.*
|
||||||
|
import kotlinx.android.synthetic.main.activity_choose_application.action_back
|
||||||
|
import kotlinx.android.synthetic.main.activity_choose_application.clear_search
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.list_view
|
import kotlinx.android.synthetic.main.activity_choose_application.list_view
|
||||||
|
import kotlinx.android.synthetic.main.activity_choose_application.loader
|
||||||
|
import kotlinx.android.synthetic.main.activity_choose_application.search
|
||||||
|
import kotlinx.android.synthetic.main.activity_music_players_filter.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
|
||||||
@ -87,6 +93,7 @@ class ChooseApplicationActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun subscribeUi(binding: ActivityChooseApplicationBinding, viewModel: ChooseApplicationViewModel) {
|
private fun subscribeUi(binding: ActivityChooseApplicationBinding, viewModel: ChooseApplicationViewModel) {
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
|
||||||
viewModel.appList.observe(this, Observer {
|
viewModel.appList.observe(this, Observer {
|
||||||
updateList(list = it)
|
updateList(list = it)
|
||||||
@ -95,6 +102,7 @@ class ChooseApplicationActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
viewModel.searchInput.observe(this, Observer { search ->
|
viewModel.searchInput.observe(this, Observer { search ->
|
||||||
updateList(search = search)
|
updateList(search = search)
|
||||||
|
clear_search.isVisible = search.isNotBlank()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +131,10 @@ class ChooseApplicationActivity : AppCompatActivity() {
|
|||||||
action_back.setOnClickListener {
|
action_back.setOnClickListener {
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear_search.setOnClickListener {
|
||||||
|
viewModel.searchInput.value = ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun saveApp(app: ResolveInfo) {
|
private fun saveApp(app: ResolveInfo) {
|
||||||
|
@ -73,6 +73,7 @@ class CustomDateActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun subscribeUi(binding: ActivityCustomDateBinding, viewModel: CustomDateViewModel) {
|
private fun subscribeUi(binding: ActivityCustomDateBinding, viewModel: CustomDateViewModel) {
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
|
||||||
viewModel.dateInput.observe(this, Observer { dateFormat ->
|
viewModel.dateInput.observe(this, Observer { dateFormat ->
|
||||||
formatJob?.cancel()
|
formatJob?.cancel()
|
||||||
|
@ -29,6 +29,12 @@ import com.tommasoberlose.anotherwidget.helpers.DateHelper
|
|||||||
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.CustomFontViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.CustomFontViewModel
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.*
|
import kotlinx.android.synthetic.main.activity_choose_application.*
|
||||||
|
import kotlinx.android.synthetic.main.activity_choose_application.action_back
|
||||||
|
import kotlinx.android.synthetic.main.activity_choose_application.clear_search
|
||||||
|
import kotlinx.android.synthetic.main.activity_choose_application.list_view
|
||||||
|
import kotlinx.android.synthetic.main.activity_choose_application.loader
|
||||||
|
import kotlinx.android.synthetic.main.activity_choose_application.search
|
||||||
|
import kotlinx.android.synthetic.main.activity_music_players_filter.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
import net.idik.lib.slimadapter.diff.DefaultDiffCallback
|
import net.idik.lib.slimadapter.diff.DefaultDiffCallback
|
||||||
@ -152,6 +158,7 @@ class CustomFontActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun subscribeUi(binding: ActivityCustomFontBinding, viewModel: CustomFontViewModel) {
|
private fun subscribeUi(binding: ActivityCustomFontBinding, viewModel: CustomFontViewModel) {
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
|
||||||
viewModel.fontList.observe(this, Observer {
|
viewModel.fontList.observe(this, Observer {
|
||||||
updateList(list = it)
|
updateList(list = it)
|
||||||
@ -160,6 +167,7 @@ class CustomFontActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
viewModel.searchInput.observe(this, Observer { search ->
|
viewModel.searchInput.observe(this, Observer { search ->
|
||||||
updateList(search = search)
|
updateList(search = search)
|
||||||
|
clear_search.isVisible = search.isNotBlank()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,6 +219,10 @@ class CustomFontActivity : AppCompatActivity() {
|
|||||||
action_back.setOnClickListener {
|
action_back.setOnClickListener {
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear_search.setOnClickListener {
|
||||||
|
viewModel.searchInput.value = ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun saveFont(font: Font, variantPos: Int? = null) {
|
private fun saveFont(font: Font, variantPos: Int? = null) {
|
||||||
|
@ -15,6 +15,7 @@ import android.view.Window
|
|||||||
import android.widget.AdapterView
|
import android.widget.AdapterView
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
@ -35,6 +36,11 @@ import com.tommasoberlose.anotherwidget.global.Preferences
|
|||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.CustomLocationViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.CustomLocationViewModel
|
||||||
import kotlinx.android.synthetic.main.activity_custom_location.*
|
import kotlinx.android.synthetic.main.activity_custom_location.*
|
||||||
|
import kotlinx.android.synthetic.main.activity_custom_location.action_back
|
||||||
|
import kotlinx.android.synthetic.main.activity_custom_location.clear_search
|
||||||
|
import kotlinx.android.synthetic.main.activity_custom_location.list_view
|
||||||
|
import kotlinx.android.synthetic.main.activity_custom_location.loader
|
||||||
|
import kotlinx.android.synthetic.main.activity_music_players_filter.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
@ -99,6 +105,8 @@ class CustomLocationActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun subscribeUi(binding: ActivityCustomLocationBinding, viewModel: CustomLocationViewModel) {
|
private fun subscribeUi(binding: ActivityCustomLocationBinding, viewModel: CustomLocationViewModel) {
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
|
||||||
viewModel.addresses.observe(this, Observer {
|
viewModel.addresses.observe(this, Observer {
|
||||||
adapter.updateData(listOf("Default") + it)
|
adapter.updateData(listOf("Default") + it)
|
||||||
loader.visibility = View.INVISIBLE
|
loader.visibility = View.INVISIBLE
|
||||||
@ -125,6 +133,7 @@ class CustomLocationActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
clear_search.isVisible = location.isNotBlank()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,5 +171,9 @@ class CustomLocationActivity : AppCompatActivity() {
|
|||||||
action_back.setOnClickListener {
|
action_back.setOnClickListener {
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear_search.setOnClickListener {
|
||||||
|
viewModel.locationInput.value = ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import android.view.View
|
|||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
@ -24,8 +25,7 @@ import com.tommasoberlose.anotherwidget.global.Preferences
|
|||||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MusicPlayersFilterViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MusicPlayersFilterViewModel
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.*
|
import kotlinx.android.synthetic.main.activity_music_players_filter.*
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.list_view
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
import kotlin.Comparator as Comparator1
|
import kotlin.Comparator as Comparator1
|
||||||
@ -81,6 +81,7 @@ class MusicPlayersFilterActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun subscribeUi(binding: ActivityMusicPlayersFilterBinding, viewModel: MusicPlayersFilterViewModel) {
|
private fun subscribeUi(binding: ActivityMusicPlayersFilterBinding, viewModel: MusicPlayersFilterViewModel) {
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
|
||||||
viewModel.appList.observe(this, Observer {
|
viewModel.appList.observe(this, Observer {
|
||||||
updateList(list = it)
|
updateList(list = it)
|
||||||
@ -89,10 +90,12 @@ class MusicPlayersFilterActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
viewModel.searchInput.observe(this, Observer { search ->
|
viewModel.searchInput.observe(this, Observer { search ->
|
||||||
updateList(search = search)
|
updateList(search = search)
|
||||||
|
clear_search.isVisible = search.isNotBlank()
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.musicPlayersFilter.observe(this, {
|
viewModel.musicPlayersFilter.observe(this, {
|
||||||
updateList()
|
updateList()
|
||||||
|
clear_selection.isVisible = Preferences.musicPlayersFilter != ""
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,6 +136,14 @@ class MusicPlayersFilterActivity : AppCompatActivity() {
|
|||||||
action_back.setOnClickListener {
|
action_back.setOnClickListener {
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear_search.setOnClickListener {
|
||||||
|
viewModel.searchInput.value = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_selection.setOnClickListener {
|
||||||
|
Preferences.musicPlayersFilter = ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleApp(app: ResolveInfo) {
|
private fun toggleApp(app: ResolveInfo) {
|
||||||
|
@ -151,7 +151,7 @@ class CalendarTabFragment : Fragment() {
|
|||||||
viewModel.calendarAppName.observe(viewLifecycleOwner, Observer {
|
viewModel.calendarAppName.observe(viewLifecycleOwner, Observer {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
calendar_app_label?.text = when {
|
calendar_app_label?.text = when {
|
||||||
Preferences.clockAppName != "" -> Preferences.clockAppName
|
Preferences.calendarAppName != "" -> Preferences.calendarAppName
|
||||||
else -> {
|
else -> {
|
||||||
if (IntentHelper.getCalendarIntent(requireContext()).isDefaultSet(requireContext())) {
|
if (IntentHelper.getCalendarIntent(requireContext()).isDefaultSet(requireContext())) {
|
||||||
getString(
|
getString(
|
||||||
|
@ -7,53 +7,51 @@ 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.graphics.Canvas
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Settings
|
|
||||||
import android.util.Log
|
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 androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
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 androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.gms.auth.api.signin.GoogleSignIn
|
import com.google.android.gms.auth.api.signin.GoogleSignIn
|
||||||
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
|
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
|
||||||
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
|
|
||||||
import com.google.android.gms.common.api.ApiException
|
import com.google.android.gms.common.api.ApiException
|
||||||
import com.karumi.dexter.Dexter
|
import com.google.android.material.card.MaterialCardView
|
||||||
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.CustomNotesDialog
|
import com.tommasoberlose.anotherwidget.components.CustomNotesDialog
|
||||||
import com.tommasoberlose.anotherwidget.components.GlanceProviderSortMenu
|
import com.tommasoberlose.anotherwidget.components.GlanceSettingsDialog
|
||||||
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
|
||||||
import com.tommasoberlose.anotherwidget.databinding.FragmentGlanceSettingsBinding
|
import com.tommasoberlose.anotherwidget.databinding.FragmentGlanceSettingsBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||||
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
|
||||||
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver.Companion.FITNESS_OPTIONS
|
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.activities.MusicPlayersFilterActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkIfFitInstalled
|
import com.tommasoberlose.anotherwidget.utils.convertDpToPixel
|
||||||
import com.tommasoberlose.anotherwidget.utils.toast
|
|
||||||
import kotlinx.android.synthetic.main.fragment_calendar_settings.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_glance_settings.*
|
import kotlinx.android.synthetic.main.fragment_glance_settings.*
|
||||||
import kotlinx.android.synthetic.main.fragment_glance_settings.scrollView
|
|
||||||
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() {
|
||||||
@ -62,6 +60,8 @@ class GlanceTabFragment : Fragment() {
|
|||||||
fun newInstance() = GlanceTabFragment()
|
fun newInstance() = GlanceTabFragment()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var dialog: GlanceSettingsDialog? = null
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
private lateinit var viewModel: MainViewModel
|
private lateinit var viewModel: MainViewModel
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@ -70,11 +70,14 @@ class GlanceTabFragment : Fragment() {
|
|||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?,
|
||||||
): View {
|
): View {
|
||||||
|
|
||||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||||
val binding = DataBindingUtil.inflate<FragmentGlanceSettingsBinding>(inflater, R.layout.fragment_glance_settings, container, false)
|
val binding = DataBindingUtil.inflate<FragmentGlanceSettingsBinding>(inflater,
|
||||||
|
R.layout.fragment_glance_settings,
|
||||||
|
container,
|
||||||
|
false)
|
||||||
|
|
||||||
subscribeUi(binding, viewModel)
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
@ -87,63 +90,242 @@ class GlanceTabFragment : Fragment() {
|
|||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
action_show_steps.isVisible = requireContext().checkIfFitInstalled()
|
// List
|
||||||
|
providers_list.setHasFixedSize(true)
|
||||||
|
val mLayoutManager = LinearLayoutManager(context)
|
||||||
|
providers_list.layoutManager = mLayoutManager
|
||||||
|
|
||||||
|
adapter = SlimAdapter.create()
|
||||||
|
adapter
|
||||||
|
.register<GlanceProvider>(R.layout.glance_provider_item) { item, injector ->
|
||||||
|
val provider = Constants.GlanceProviderId.from(item.id)!!
|
||||||
|
injector
|
||||||
|
.text(R.id.title, item.title)
|
||||||
|
.with<ImageView>(R.id.icon) {
|
||||||
|
it.setImageDrawable(ContextCompat.getDrawable(requireContext(), item.icon))
|
||||||
|
}
|
||||||
|
.clicked(R.id.item) {
|
||||||
|
if (Preferences.showGlance) {
|
||||||
|
if (provider == Constants.GlanceProviderId.CUSTOM_INFO) {
|
||||||
|
CustomNotesDialog(requireContext()).show()
|
||||||
|
} else {
|
||||||
|
dialog = GlanceSettingsDialog(requireActivity(), provider) {
|
||||||
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
|
}
|
||||||
|
dialog?.setOnDismissListener {
|
||||||
|
dialog = null
|
||||||
|
}
|
||||||
|
dialog?.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
when (provider) {
|
||||||
|
Constants.GlanceProviderId.PLAYING_SONG -> {
|
||||||
|
when {
|
||||||
|
ActiveNotificationsHelper.checkNotificationAccess(requireContext()) -> {
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
injector.text(R.id.label,
|
||||||
|
if (Preferences.showMusic) getString(R.string.settings_visible) else getString(
|
||||||
|
R.string.settings_not_visible))
|
||||||
|
}
|
||||||
|
Preferences.showMusic -> {
|
||||||
|
injector.visibility(R.id.error_icon, View.VISIBLE)
|
||||||
|
injector.visibility(R.id.info_icon, View.GONE)
|
||||||
|
injector.text(R.id.label, getString(R.string.settings_not_visible))
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
injector.text(R.id.label, getString(R.string.settings_not_visible))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||||
|
injector.text(R.id.label,
|
||||||
|
if (Preferences.showNextAlarm && !AlarmHelper.isAlarmProbablyWrong(
|
||||||
|
requireContext())
|
||||||
|
) getString(R.string.settings_visible) else getString(
|
||||||
|
R.string.settings_not_visible))
|
||||||
|
injector.visibility(R.id.error_icon,
|
||||||
|
if (Preferences.showNextAlarm && AlarmHelper.isAlarmProbablyWrong(
|
||||||
|
requireContext())
|
||||||
|
) View.VISIBLE else View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon,
|
||||||
|
if (!(Preferences.showNextAlarm && AlarmHelper.isAlarmProbablyWrong(
|
||||||
|
requireContext()))
|
||||||
|
) View.VISIBLE else View.GONE)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||||
|
injector.text(R.id.label,
|
||||||
|
if (Preferences.showBatteryCharging) getString(R.string.settings_visible) else getString(
|
||||||
|
R.string.settings_not_visible))
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.NOTIFICATIONS -> {
|
||||||
|
when {
|
||||||
|
ActiveNotificationsHelper.checkNotificationAccess(requireContext()) -> {
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
injector.text(R.id.label,
|
||||||
|
if (Preferences.showNotifications) getString(
|
||||||
|
R.string.settings_visible) else getString(R.string.settings_not_visible))
|
||||||
|
}
|
||||||
|
Preferences.showNotifications -> {
|
||||||
|
injector.visibility(R.id.error_icon, View.VISIBLE)
|
||||||
|
injector.visibility(R.id.info_icon, View.GONE)
|
||||||
|
injector.text(R.id.label, getString(R.string.settings_not_visible))
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
injector.text(R.id.label, getString(R.string.settings_not_visible))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.GREETINGS -> {
|
||||||
|
injector.text(R.id.label,
|
||||||
|
if (Preferences.showGreetings) getString(R.string.settings_visible) else getString(
|
||||||
|
R.string.settings_not_visible))
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
||||||
|
injector.text(R.id.label,
|
||||||
|
if (Preferences.customNotes != "") getString(R.string.settings_visible) else getString(
|
||||||
|
R.string.settings_not_visible))
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
||||||
|
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(context)
|
||||||
|
if (GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS) && (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || activity?.checkGrantedPermission(
|
||||||
|
Manifest.permission.ACTIVITY_RECOGNITION) == true)
|
||||||
|
) {
|
||||||
|
injector.text(R.id.label,
|
||||||
|
if (Preferences.showDailySteps) getString(R.string.settings_visible) else getString(
|
||||||
|
R.string.settings_not_visible))
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
} else if (Preferences.showDailySteps) {
|
||||||
|
ActivityDetectionReceiver.unregisterFence(requireContext())
|
||||||
|
injector.visibility(R.id.error_icon, View.VISIBLE)
|
||||||
|
injector.visibility(R.id.info_icon, View.GONE)
|
||||||
|
injector.text(R.id.label, getString(R.string.settings_not_visible))
|
||||||
|
} else {
|
||||||
|
ActivityDetectionReceiver.unregisterFence(requireContext())
|
||||||
|
injector.text(R.id.label, getString(R.string.settings_not_visible))
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.attachTo(providers_list)
|
||||||
|
|
||||||
|
val mIth = ItemTouchHelper(
|
||||||
|
object : ItemTouchHelper.SimpleCallback(
|
||||||
|
ItemTouchHelper.UP or ItemTouchHelper.DOWN,
|
||||||
|
0
|
||||||
|
) {
|
||||||
|
|
||||||
|
val list = GlanceProviderHelper.getGlanceProviders(requireContext())
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
Collections.swap(list, fromPos, toPos)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isItemViewSwipeEnabled(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearView(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder
|
||||||
|
) {
|
||||||
|
super.clearView(recyclerView, viewHolder)
|
||||||
|
GlanceProviderHelper.saveGlanceProviderOrder(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onChildDraw(
|
||||||
|
c: Canvas,
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
dX: Float,
|
||||||
|
dY: Float,
|
||||||
|
actionState: Int,
|
||||||
|
isCurrentlyActive: Boolean,
|
||||||
|
) {
|
||||||
|
val view = viewHolder.itemView as MaterialCardView
|
||||||
|
if (isCurrentlyActive) {
|
||||||
|
ViewCompat.setElevation(view, 2f.convertDpToPixel(requireContext()))
|
||||||
|
view.setCardBackgroundColor(ContextCompat.getColor(requireContext(),
|
||||||
|
R.color.colorPrimary))
|
||||||
|
} else {
|
||||||
|
ViewCompat.setElevation(view, 0f)
|
||||||
|
view.setCardBackgroundColor(ContextCompat.getColor(requireContext(),
|
||||||
|
R.color.colorPrimaryDark))
|
||||||
|
}
|
||||||
|
|
||||||
|
val topEdge = if ((view.top == 0 && dY < 0) || ((view.top + view.height >= recyclerView.height - 32f.convertDpToPixel(requireContext())) && dY > 0)) 0f else dY
|
||||||
|
Log.d("ciao", "${view.top} + ${view.height} = ${view.top + view.height} to compare to ${recyclerView.height} - ${32f.convertDpToPixel(requireContext())}")
|
||||||
|
|
||||||
|
super.onChildDraw(c,
|
||||||
|
recyclerView,
|
||||||
|
viewHolder,
|
||||||
|
dX,
|
||||||
|
topEdge,
|
||||||
|
actionState,
|
||||||
|
isCurrentlyActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSwiped(
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
direction: Int,
|
||||||
|
) {
|
||||||
|
// remove from adapter
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
mIth.attachToRecyclerView(providers_list)
|
||||||
|
adapter.updateData(
|
||||||
|
GlanceProviderHelper.getGlanceProviders(requireContext())
|
||||||
|
.mapNotNull { GlanceProviderHelper.getGlanceProviderById(requireContext(), it) }
|
||||||
|
.filterNot { it.id == Constants.GlanceProviderId.GREETINGS.id }
|
||||||
|
)
|
||||||
|
providers_list.isNestedScrollingEnabled = false
|
||||||
|
|
||||||
setupListener()
|
setupListener()
|
||||||
updateNextAlarmWarningUi()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun subscribeUi(
|
private fun subscribeUi(
|
||||||
binding: FragmentGlanceSettingsBinding,
|
binding: FragmentGlanceSettingsBinding,
|
||||||
viewModel: MainViewModel
|
viewModel: MainViewModel,
|
||||||
) {
|
) {
|
||||||
binding.isGlanceVisible = Preferences.showGlance
|
binding.isGlanceVisible = Preferences.showGlance
|
||||||
|
|
||||||
viewModel.showGlance.observe(viewLifecycleOwner, Observer {
|
viewModel.showGlance.observe(viewLifecycleOwner, Observer {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
binding.isGlanceVisible = it
|
binding.isGlanceVisible = it
|
||||||
show_glance_label.text = if (it) getString(R.string.description_show_glance_visible) else getString(R.string.description_show_glance_not_visible)
|
show_glance_label.text =
|
||||||
|
if (it) getString(R.string.description_show_glance_visible) else getString(
|
||||||
|
R.string.description_show_glance_not_visible)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.showMusic.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
checkNotificationPermission()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.showNextAlarm.observe(viewLifecycleOwner, Observer {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.musicPlayersFilter.observe(viewLifecycleOwner, Observer {
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupListener() {
|
private fun setupListener() {
|
||||||
|
|
||||||
action_show_glance.setOnClickListener {
|
action_show_glance.setOnClickListener {
|
||||||
Preferences.showGlance = !Preferences.showGlance
|
Preferences.showGlance = !Preferences.showGlance
|
||||||
}
|
}
|
||||||
@ -151,134 +333,21 @@ class GlanceTabFragment : Fragment() {
|
|||||||
show_glance_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
show_glance_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
||||||
Preferences.showGlance = enabled
|
Preferences.showGlance = enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
action_sort_glance_providers.setOnClickListener {
|
|
||||||
GlanceProviderSortMenu(requireContext())
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_music.setOnClickListener {
|
|
||||||
if (Preferences.showGlance) {
|
|
||||||
BottomSheetMenu<Boolean>(
|
|
||||||
requireContext(),
|
|
||||||
header = getString(R.string.settings_show_music_title)
|
|
||||||
).setSelectedValue(Preferences.showMusic)
|
|
||||||
.addItem(getString(R.string.settings_visible), true)
|
|
||||||
.addItem(getString(R.string.settings_not_visible), false)
|
|
||||||
.addOnSelectItemListener { value ->
|
|
||||||
Preferences.showMusic = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_next_alarm.setOnClickListener {
|
|
||||||
if (Preferences.showGlance) {
|
|
||||||
BottomSheetMenu<Boolean>(
|
|
||||||
requireContext(),
|
|
||||||
header = getString(R.string.settings_show_next_alarm_title)
|
|
||||||
).setSelectedValue(Preferences.showNextAlarm)
|
|
||||||
.addItem(getString(R.string.settings_visible), true)
|
|
||||||
.addItem(getString(R.string.settings_not_visible), false)
|
|
||||||
.addOnSelectItemListener { value ->
|
|
||||||
Preferences.showNextAlarm = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_next_alarm.setOnLongClickListener {
|
|
||||||
with(requireContext().getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
|
||||||
val alarm = nextAlarmClock
|
|
||||||
if (alarm != null && alarm.showIntent != null) {
|
|
||||||
val pm = requireContext().packageManager as PackageManager
|
|
||||||
val appNameOrPackage = try {
|
|
||||||
pm.getApplicationLabel(pm.getApplicationInfo(alarm.showIntent?.creatorPackage ?: "", 0))
|
|
||||||
} catch (e: Exception) {
|
|
||||||
alarm.showIntent?.creatorPackage ?: ""
|
|
||||||
}
|
|
||||||
MaterialBottomSheetDialog(requireContext(), message = getString(R.string.next_alarm_warning).format(appNameOrPackage))
|
|
||||||
.setPositiveButton(getString(android.R.string.ok))
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_filter_music_players.setOnClickListener {
|
|
||||||
startActivity(Intent(requireContext(), MusicPlayersFilterActivity::class.java))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateNextAlarmWarningUi() {
|
|
||||||
with(requireContext().getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
|
||||||
val alarm = nextAlarmClock
|
|
||||||
if (AlarmHelper.isAlarmProbablyWrong(requireContext()) && alarm != null && alarm.showIntent != null) {
|
|
||||||
val pm = requireContext().packageManager as PackageManager
|
|
||||||
val appNameOrPackage = try {
|
|
||||||
pm.getApplicationLabel(pm.getApplicationInfo(alarm.showIntent?.creatorPackage ?: "", 0))
|
|
||||||
} catch (e: Exception) {
|
|
||||||
alarm.showIntent?.creatorPackage ?: ""
|
|
||||||
}
|
|
||||||
show_next_alarm_warning.text = getString(R.string.next_alarm_warning).format(appNameOrPackage)
|
|
||||||
} else {
|
|
||||||
show_next_alarm_label?.text = if (Preferences.showNextAlarm) getString(R.string.settings_visible) else getString(
|
|
||||||
R.string.settings_not_visible)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val nextAlarmChangeBroadcastReceiver = object : BroadcastReceiver() {
|
private val nextAlarmChangeBroadcastReceiver = object : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
updateNextAlarmWarningUi()
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
activity?.registerReceiver(nextAlarmChangeBroadcastReceiver, IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED))
|
activity?.registerReceiver(nextAlarmChangeBroadcastReceiver,
|
||||||
|
IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED))
|
||||||
|
if (dialog != null) {
|
||||||
|
dialog?.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
@ -286,66 +355,27 @@ class GlanceTabFragment : Fragment() {
|
|||||||
super.onStop()
|
super.onStop()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkNotificationPermission() {
|
|
||||||
when {
|
|
||||||
NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName) -> {
|
|
||||||
notification_permission_alert?.isVisible = false
|
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
|
||||||
show_music_label?.text = if (Preferences.showMusic) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
|
||||||
}
|
|
||||||
Preferences.showMusic -> {
|
|
||||||
notification_permission_alert?.isVisible = true
|
|
||||||
show_music_label?.text = getString(R.string.settings_request_notification_access)
|
|
||||||
notification_permission_alert?.setOnClickListener {
|
|
||||||
activity?.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
show_music_label?.text = getString(R.string.settings_not_visible)
|
|
||||||
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(
|
override fun onActivityResult(
|
||||||
requestCode: Int,
|
requestCode: Int,
|
||||||
resultCode: Int,
|
resultCode: Int,
|
||||||
data: Intent?
|
data: Intent?,
|
||||||
) {
|
) {
|
||||||
when (requestCode) {
|
when (requestCode) {
|
||||||
1 -> {
|
1 -> {
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
checkFitnessPermission()
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
} else {
|
} else {
|
||||||
Preferences.showDailySteps = false
|
Preferences.showDailySteps = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dialog != null) {
|
||||||
|
dialog?.show()
|
||||||
}
|
}
|
||||||
2-> {
|
}
|
||||||
|
2 -> {
|
||||||
try {
|
try {
|
||||||
val account: GoogleSignInAccount? = GoogleSignIn.getSignedInAccountFromIntent(data).getResult(ApiException::class.java)
|
val account: GoogleSignInAccount? = GoogleSignIn.getSignedInAccountFromIntent(
|
||||||
|
data).getResult(ApiException::class.java)
|
||||||
if (!GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS)) {
|
if (!GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS)) {
|
||||||
GoogleSignIn.requestPermissions(
|
GoogleSignIn.requestPermissions(
|
||||||
requireActivity(),
|
requireActivity(),
|
||||||
@ -353,40 +383,18 @@ class GlanceTabFragment : Fragment() {
|
|||||||
account,
|
account,
|
||||||
FITNESS_OPTIONS)
|
FITNESS_OPTIONS)
|
||||||
} else {
|
} else {
|
||||||
checkFitnessPermission()
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
}
|
}
|
||||||
} catch (e: ApiException) {
|
} catch (e: ApiException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
Preferences.showDailySteps = false
|
Preferences.showDailySteps = false
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun requireFitnessPermission() {
|
if (dialog != null) {
|
||||||
Dexter.withContext(requireContext())
|
dialog?.show()
|
||||||
.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) {
|
||||||
@ -400,6 +408,9 @@ class GlanceTabFragment : Fragment() {
|
|||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
checkNotificationPermission()
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
|
if (dialog != null) {
|
||||||
|
dialog?.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,9 @@ import com.tommasoberlose.anotherwidget.R
|
|||||||
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
||||||
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.helpers.BitmapHelper
|
import com.tommasoberlose.anotherwidget.helpers.*
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
||||||
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
|
||||||
import com.tommasoberlose.anotherwidget.helpers.WidgetHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
import com.tommasoberlose.anotherwidget.ui.adapters.ViewPagerAdapter
|
import com.tommasoberlose.anotherwidget.ui.adapters.ViewPagerAdapter
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
@ -74,8 +72,6 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
|||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
subscribeUi(viewModel)
|
|
||||||
|
|
||||||
// Viewpager
|
// Viewpager
|
||||||
pager.adapter = ViewPagerAdapter(requireActivity())
|
pager.adapter = ViewPagerAdapter(requireActivity())
|
||||||
pager.offscreenPageLimit = 4
|
pager.offscreenPageLimit = 4
|
||||||
@ -91,17 +87,20 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
|||||||
}.attach()
|
}.attach()
|
||||||
|
|
||||||
// Init clock
|
// Init clock
|
||||||
|
if (Preferences.showClock) {
|
||||||
time.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
|
time.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
|
||||||
time.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(requireContext()))
|
time.setTextSize(TypedValue.COMPLEX_UNIT_SP,
|
||||||
|
Preferences.clockTextSize.toPixel(requireContext()))
|
||||||
time_am_pm.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
|
time_am_pm.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
|
||||||
time_am_pm.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2)
|
time_am_pm.setTextSize(TypedValue.COMPLEX_UNIT_SP,
|
||||||
|
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2)
|
||||||
|
}
|
||||||
time_container.isVisible = Preferences.showClock
|
time_container.isVisible = Preferences.showClock
|
||||||
|
|
||||||
preview.layoutParams = preview.layoutParams.apply {
|
preview.layoutParams = preview.layoutParams.apply {
|
||||||
height = PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(requireContext()) else 0
|
height = PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(requireContext()) else 0
|
||||||
}
|
}
|
||||||
subscribeUi(viewModel)
|
subscribeUi(viewModel)
|
||||||
updateUI()
|
|
||||||
|
|
||||||
// Warnings
|
// Warnings
|
||||||
if (getString(R.string.xiaomi_manufacturer).equals(Build.MANUFACTURER, ignoreCase = true) && Preferences.showXiaomiWarning) {
|
if (getString(R.string.xiaomi_manufacturer).equals(Build.MANUFACTURER, ignoreCase = true) && Preferences.showXiaomiWarning) {
|
||||||
@ -359,11 +358,13 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Music error indicator
|
// Glance error indicator
|
||||||
tabs?.getTabAt(4)?.orCreateBadge?.apply {
|
tabs?.getTabAt(4)?.orCreateBadge?.apply {
|
||||||
backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText)
|
backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText)
|
||||||
badgeGravity = BadgeDrawable.TOP_END
|
badgeGravity = BadgeDrawable.TOP_END
|
||||||
}?.isVisible = Preferences.showMusic && !NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName)
|
}?.isVisible = ((Preferences.showMusic || Preferences.showNotifications) && !ActiveNotificationsHelper.checkNotificationAccess(requireContext())) ||
|
||||||
|
(Preferences.showDailySteps && !(Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || requireActivity().checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION))) ||
|
||||||
|
(AlarmHelper.isAlarmProbablyWrong(requireContext()))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
@ -26,6 +26,7 @@ import com.tommasoberlose.anotherwidget.R
|
|||||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||||
import com.tommasoberlose.anotherwidget.databinding.FragmentSettingsBinding
|
import com.tommasoberlose.anotherwidget.databinding.FragmentSettingsBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.SupportDevActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.SupportDevActivity
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
@ -131,9 +132,6 @@ class SettingsFragment : Fragment() {
|
|||||||
Preferences.showPreview = isChecked
|
Preferences.showPreview = isChecked
|
||||||
}
|
}
|
||||||
|
|
||||||
action_show_wallpaper.setOnClickListener {
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_wallpaper.setOnClickListener {
|
action_show_wallpaper.setOnClickListener {
|
||||||
show_wallpaper_toggle.isChecked = !show_wallpaper_toggle.isChecked
|
show_wallpaper_toggle.isChecked = !show_wallpaper_toggle.isChecked
|
||||||
}
|
}
|
||||||
@ -198,6 +196,7 @@ class SettingsFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
CalendarHelper.updateEventList(requireContext())
|
CalendarHelper.updateEventList(requireContext())
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
||||||
|
ActiveNotificationsHelper.clearLastNotification(requireContext())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.ResolveInfo
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.chibatching.kotpref.livedata.asLiveData
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
|
||||||
|
class AppNotificationsViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
|
|
||||||
|
val pm: PackageManager by lazy { application.packageManager }
|
||||||
|
val appList: MutableLiveData<List<ResolveInfo>> = MutableLiveData()
|
||||||
|
val searchInput: MutableLiveData<String> = MutableLiveData("")
|
||||||
|
var appNotificationsFilter = Preferences.asLiveData(Preferences::appNotificationsFilter)
|
||||||
|
|
||||||
|
init {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
val mainIntent = Intent(Intent.ACTION_MAIN, null).apply {
|
||||||
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
}
|
||||||
|
|
||||||
|
val app = application.packageManager.queryIntentActivities(mainIntent, 0)
|
||||||
|
val sortedApp = app.sortedWith(Comparator { app1: ResolveInfo, app2: ResolveInfo ->
|
||||||
|
app1.loadLabel(pm).toString().compareTo(app2.loadLabel(pm).toString())
|
||||||
|
})
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
appList.postValue(sortedApp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,23 +7,21 @@ import android.appwidget.AppWidgetProvider
|
|||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.IntentSender
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
|
||||||
import android.os.HandlerThread
|
|
||||||
import android.os.Looper
|
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.widget.ImageView
|
||||||
import android.widget.*
|
import android.widget.RemoteViews
|
||||||
|
import android.widget.TextView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.provider.FontRequest
|
|
||||||
import androidx.core.provider.FontsContractCompat
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import com.google.gson.Gson
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.db.EventRepository
|
import com.tommasoberlose.anotherwidget.db.EventRepository
|
||||||
import com.tommasoberlose.anotherwidget.global.Actions
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
@ -32,9 +30,10 @@ import com.tommasoberlose.anotherwidget.global.Preferences
|
|||||||
import com.tommasoberlose.anotherwidget.helpers.*
|
import com.tommasoberlose.anotherwidget.helpers.*
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||||
import com.tommasoberlose.anotherwidget.receivers.*
|
import com.tommasoberlose.anotherwidget.receivers.*
|
||||||
import com.tommasoberlose.anotherwidget.utils.*
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.toPixel
|
||||||
import kotlinx.android.synthetic.main.the_widget.view.*
|
import kotlinx.android.synthetic.main.the_widget.view.*
|
||||||
import java.lang.Exception
|
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
@ -348,6 +347,26 @@ class MainWidget : AppWidgetProvider() {
|
|||||||
break@loop
|
break@loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Constants.GlanceProviderId.NOTIFICATIONS -> {
|
||||||
|
if (Preferences.showNotifications && ActiveNotificationsHelper.showLastNotification()) {
|
||||||
|
try {
|
||||||
|
val remotePackageContext = context.createPackageContext(Preferences.lastNotificationPackage, 0)
|
||||||
|
val icon = ContextCompat.getDrawable(remotePackageContext, Preferences.lastNotificationIcon)
|
||||||
|
val notificationIntent = PendingIntent.getActivity(
|
||||||
|
context,
|
||||||
|
widgetID,
|
||||||
|
IntentHelper.getNotificationIntent(context),
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
|
)
|
||||||
|
views.setOnClickPendingIntent(
|
||||||
|
R.id.second_row_rect,
|
||||||
|
notificationIntent
|
||||||
|
)
|
||||||
|
showSomething = true
|
||||||
|
break@loop
|
||||||
|
} catch (ex: Exception) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -695,6 +714,19 @@ class MainWidget : AppWidgetProvider() {
|
|||||||
break@loop
|
break@loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Constants.GlanceProviderId.NOTIFICATIONS -> {
|
||||||
|
if (Preferences.showNotifications && ActiveNotificationsHelper.showLastNotification()) {
|
||||||
|
try {
|
||||||
|
val remotePackageContext = context.createPackageContext(Preferences.lastNotificationPackage, 0)
|
||||||
|
val icon = ContextCompat.getDrawable(remotePackageContext, Preferences.lastNotificationIcon)
|
||||||
|
v.second_row_icon.isVisible = true
|
||||||
|
v.second_row_icon.setImageDrawable(icon)
|
||||||
|
v.next_event_date.text = Preferences.lastNotificationTitle
|
||||||
|
showSomething = true
|
||||||
|
break@loop
|
||||||
|
} catch (ex: Exception) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIN
app/src/main/res/drawable-hdpi/round_arrow_circle_down.png
Normal file
After Width: | Height: | Size: 536 B |
After Width: | Height: | Size: 466 B |
After Width: | Height: | Size: 778 B |
After Width: | Height: | Size: 1005 B |
BIN
app/src/main/res/drawable-hdpi/round_check_circle_outline.png
Normal file
After Width: | Height: | Size: 817 B |
After Width: | Height: | Size: 469 B |
After Width: | Height: | Size: 558 B |
After Width: | Height: | Size: 1.0 KiB |
BIN
app/src/main/res/drawable-hdpi/round_clear_all.png
Normal file
After Width: | Height: | Size: 175 B |
BIN
app/src/main/res/drawable-hdpi/round_clear_all_white_24.png
Normal file
After Width: | Height: | Size: 131 B |
BIN
app/src/main/res/drawable-hdpi/round_clear_all_white_36.png
Normal file
After Width: | Height: | Size: 226 B |
BIN
app/src/main/res/drawable-hdpi/round_clear_all_white_48.png
Normal file
After Width: | Height: | Size: 188 B |
BIN
app/src/main/res/drawable-hdpi/round_history_edu.png
Normal file
After Width: | Height: | Size: 604 B |
BIN
app/src/main/res/drawable-hdpi/round_history_edu_black_18.png
Normal file
After Width: | Height: | Size: 325 B |
BIN
app/src/main/res/drawable-hdpi/round_history_edu_black_24.png
Normal file
After Width: | Height: | Size: 381 B |
BIN
app/src/main/res/drawable-hdpi/round_history_edu_black_36.png
Normal file
After Width: | Height: | Size: 513 B |
BIN
app/src/main/res/drawable-hdpi/round_notifications.png
Normal file
After Width: | Height: | Size: 268 B |
BIN
app/src/main/res/drawable-hdpi/round_notifications_white_18.png
Normal file
After Width: | Height: | Size: 227 B |
BIN
app/src/main/res/drawable-hdpi/round_notifications_white_36.png
Normal file
After Width: | Height: | Size: 355 B |
BIN
app/src/main/res/drawable-hdpi/round_notifications_white_48.png
Normal file
After Width: | Height: | Size: 447 B |
BIN
app/src/main/res/drawable-hdpi/round_outbond.png
Normal file
After Width: | Height: | Size: 327 B |
BIN
app/src/main/res/drawable-hdpi/round_outbond_white_24.png
Normal file
After Width: | Height: | Size: 389 B |
BIN
app/src/main/res/drawable-hdpi/round_outbond_white_36.png
Normal file
After Width: | Height: | Size: 554 B |
BIN
app/src/main/res/drawable-hdpi/round_outbond_white_48.png
Normal file
After Width: | Height: | Size: 708 B |
BIN
app/src/main/res/drawable-hdpi/round_run_circle_white_18.png
Normal file
After Width: | Height: | Size: 386 B |
BIN
app/src/main/res/drawable-hdpi/round_run_circle_white_24.png
Normal file
After Width: | Height: | Size: 475 B |
BIN
app/src/main/res/drawable-hdpi/round_run_circle_white_36.png
Normal file
After Width: | Height: | Size: 697 B |
BIN
app/src/main/res/drawable-hdpi/round_run_circle_white_48.png
Normal file
After Width: | Height: | Size: 905 B |
BIN
app/src/main/res/drawable-hdpi/round_save.png
Normal file
After Width: | Height: | Size: 546 B |
BIN
app/src/main/res/drawable-hdpi/round_save_white_18.png
Normal file
After Width: | Height: | Size: 274 B |
BIN
app/src/main/res/drawable-hdpi/round_save_white_24.png
Normal file
After Width: | Height: | Size: 331 B |
BIN
app/src/main/res/drawable-hdpi/round_save_white_36.png
Normal file
After Width: | Height: | Size: 436 B |
BIN
app/src/main/res/drawable-hdpi/round_select_all.png
Normal file
After Width: | Height: | Size: 278 B |
BIN
app/src/main/res/drawable-hdpi/round_select_all_white_18.png
Normal file
After Width: | Height: | Size: 259 B |
BIN
app/src/main/res/drawable-hdpi/round_select_all_white_36.png
Normal file
After Width: | Height: | Size: 354 B |
BIN
app/src/main/res/drawable-hdpi/round_select_all_white_48.png
Normal file
After Width: | Height: | Size: 352 B |
BIN
app/src/main/res/drawable-hdpi/round_sticky_note_2.png
Normal file
After Width: | Height: | Size: 347 B |
BIN
app/src/main/res/drawable-hdpi/round_sticky_note_2_white_18.png
Normal file
After Width: | Height: | Size: 237 B |
BIN
app/src/main/res/drawable-hdpi/round_sticky_note_2_white_24.png
Normal file
After Width: | Height: | Size: 259 B |
BIN
app/src/main/res/drawable-hdpi/round_sticky_note_2_white_48.png
Normal file
After Width: | Height: | Size: 398 B |
BIN
app/src/main/res/drawable-mdpi/round_arrow_circle_down.png
Normal file
After Width: | Height: | Size: 379 B |
After Width: | Height: | Size: 271 B |
After Width: | Height: | Size: 536 B |
After Width: | Height: | Size: 707 B |
BIN
app/src/main/res/drawable-mdpi/round_check_circle_outline.png
Normal file
After Width: | Height: | Size: 558 B |
After Width: | Height: | Size: 340 B |
After Width: | Height: | Size: 400 B |
After Width: | Height: | Size: 747 B |
BIN
app/src/main/res/drawable-mdpi/round_clear_all.png
Normal file
After Width: | Height: | Size: 116 B |
BIN
app/src/main/res/drawable-mdpi/round_clear_all_white_24.png
Normal file
After Width: | Height: | Size: 100 B |
BIN
app/src/main/res/drawable-mdpi/round_clear_all_white_36.png
Normal file
After Width: | Height: | Size: 131 B |
BIN
app/src/main/res/drawable-mdpi/round_clear_all_white_48.png
Normal file
After Width: | Height: | Size: 139 B |
BIN
app/src/main/res/drawable-mdpi/round_history_edu.png
Normal file
After Width: | Height: | Size: 430 B |
BIN
app/src/main/res/drawable-mdpi/round_history_edu_black_18.png
Normal file
After Width: | Height: | Size: 232 B |
BIN
app/src/main/res/drawable-mdpi/round_history_edu_black_24.png
Normal file
After Width: | Height: | Size: 255 B |
BIN
app/src/main/res/drawable-mdpi/round_history_edu_black_36.png
Normal file
After Width: | Height: | Size: 381 B |
BIN
app/src/main/res/drawable-mdpi/round_notifications.png
Normal file
After Width: | Height: | Size: 198 B |
BIN
app/src/main/res/drawable-mdpi/round_notifications_white_18.png
Normal file
After Width: | Height: | Size: 174 B |
BIN
app/src/main/res/drawable-mdpi/round_notifications_white_36.png
Normal file
After Width: | Height: | Size: 268 B |
BIN
app/src/main/res/drawable-mdpi/round_notifications_white_48.png
Normal file
After Width: | Height: | Size: 319 B |
BIN
app/src/main/res/drawable-mdpi/round_outbond.png
Normal file
After Width: | Height: | Size: 246 B |
BIN
app/src/main/res/drawable-mdpi/round_outbond_white_24.png
Normal file
After Width: | Height: | Size: 282 B |
BIN
app/src/main/res/drawable-mdpi/round_outbond_white_36.png
Normal file
After Width: | Height: | Size: 389 B |
BIN
app/src/main/res/drawable-mdpi/round_outbond_white_48.png
Normal file
After Width: | Height: | Size: 501 B |