Merge music

This commit is contained in:
Tommaso Berlose 2020-05-08 18:57:14 +02:00
commit 4cc55edb15
72 changed files with 658 additions and 128 deletions
app
build.gradle
src/main
AndroidManifest.xml
java/com/tommasoberlose/anotherwidget
res
tasksintegration/build/intermediates
bundle_manifest/debug/bundle-manifest
incremental/packageDebug/tmp/debug
instant_app_manifest/debug
manifest_merge_blame_file/debug
merged_manifests/debug
metadata_feature_manifest/debug/metadata-feature

@ -18,8 +18,8 @@ android {
applicationId "com.tommasoberlose.anotherwidget"
minSdkVersion 23
targetSdkVersion 29
versionCode 79
versionName "2.0.5"
versionCode 80
versionName "2.0.6"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

@ -139,6 +139,12 @@
<service android:name=".services.EventListenerJob" android:permission="android.permission.BIND_JOB_SERVICE" />
<service android:name=".receivers.MusicNotificationListener"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
</application>
</manifest>

@ -9,6 +9,7 @@ object Preferences : KotprefModel() {
var darkThemePreference by intPref(default = MODE_NIGHT_FOLLOW_SYSTEM)
// Calendar and weather
var showEvents by booleanPref(key = "PREF_SHOW_EVENTS", default = false)
var showWeather by booleanPref(key = "PREF_SHOW_WEATHER", default = false)
var weatherIcon by stringPref(key = "PREF_WEATHER_ICON", default = "")
@ -48,6 +49,7 @@ object Preferences : KotprefModel() {
var clockTextColor by stringPref(default = "#FFFFFF")
var clockTextAlpha by stringPref(default = "FF")
// Global
var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 26f)
var textSecondSize by floatPref(key = "PREF_TEXT_SECOND_SIZE", default = 18f)
var clockTextSize by floatPref(key = "PREF_TEXT_CLOCK_SIZE", default = 90f)
@ -64,9 +66,18 @@ object Preferences : KotprefModel() {
var customFontFile by stringPref(key = "PREF_CUSTOM_FONT_FILE")
var showNextEvent by booleanPref(key = "PREF_SHOW_NEXT_EVENT", default = true)
// Settings
var showWallpaper by booleanPref(default = true)
var showBigClockWarning by booleanPref(default = true)
var showWeatherWarning by booleanPref(default = true)
var showPreview by booleanPref(default = true)
var showXiaomiWarning by booleanPref(default = true)
// Music
var showMusic by booleanPref(default = false)
var mediaInfoFormat by stringPref(default = "")
var mediaPlayerTitle by stringPref(default = "")
var mediaPlayerAlbum by stringPref(default = "")
var mediaPlayerArtist by stringPref(default = "")
var mediaPlayerPackage by stringPref(default = "")
}

@ -160,4 +160,22 @@ object IntentHelper {
}
}
}
fun getMusicIntent(context: Context): Intent {
return when (Preferences.mediaPlayerPackage) {
"" -> {
Intent()
}
else -> {
val pm: PackageManager = context.packageManager
try {
pm.getLaunchIntentForPackage(Preferences.mediaPlayerPackage)!!.apply {
addCategory(Intent.CATEGORY_LAUNCHER)
}
} catch (e: Exception) {
Intent()
}
}
}
}
}

@ -0,0 +1,88 @@
package com.tommasoberlose.anotherwidget.helpers
import android.app.Notification
import android.content.ComponentName
import android.content.Context
import android.media.MediaMetadata
import android.media.session.MediaController
import android.media.session.MediaSession
import android.media.session.MediaSessionManager
import android.media.session.PlaybackState
import android.util.Log
import androidx.core.app.NotificationManagerCompat
import com.chibatching.kotpref.bulk
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.receivers.MusicNotificationListener
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import java.lang.Exception
object MediaPlayerHelper {
fun isSomeonePlaying(context: Context) = Preferences.showMusic && NotificationManagerCompat.getEnabledListenerPackages(context).contains(context.packageName) && Preferences.mediaPlayerTitle != ""
fun getMediaInfo(): String {
return if (Preferences.mediaPlayerArtist == "") {
Preferences.mediaPlayerTitle
} else {
"%s, %s".format(Preferences.mediaPlayerTitle, Preferences.mediaPlayerArtist)
}
}
fun updatePlayingMediaInfo(context: Context) {
if (NotificationManagerCompat.getEnabledListenerPackages(context).contains(context.packageName)) {
val list = try {
(context.getSystemService(Context.MEDIA_SESSION_SERVICE) as MediaSessionManager).getActiveSessions(
ComponentName(context.packageName, MusicNotificationListener::class.java.name)
)
} catch (ex: Exception) {
emptyList<MediaController>()
}
if (list.isNotEmpty()) {
var isSomeonePlaying = false
list.forEach { mc ->
val metadata = mc.metadata
val isPlaying =
mc.playbackState?.state == PlaybackState.STATE_PLAYING || mc.playbackState?.state == PlaybackState.STATE_CONNECTING
if (isPlaying) {
isSomeonePlaying = true
if (metadata != null) {
Preferences.bulk {
mediaPlayerTitle =
metadata.getText(MediaMetadata.METADATA_KEY_TITLE)?.toString()
?: ""
mediaPlayerArtist =
metadata.getText(MediaMetadata.METADATA_KEY_ARTIST)?.toString()
?: ""
mediaPlayerAlbum =
metadata.getText(MediaMetadata.METADATA_KEY_ALBUM)?.toString()
?: ""
}
}
Preferences.mediaPlayerPackage = mc.packageName
}
}
if (!isSomeonePlaying) {
removeMediaInfo()
}
} else {
removeMediaInfo()
}
} else {
removeMediaInfo()
}
MainWidget.updateWidget(context)
}
private fun removeMediaInfo() {
Preferences.bulk {
remove(Preferences::mediaPlayerTitle)
remove(Preferences::mediaPlayerArtist)
remove(Preferences::mediaPlayerAlbum)
remove(Preferences::mediaPlayerPackage)
}
}
}

@ -5,6 +5,7 @@ import android.content.Context
import android.os.Build
import com.google.android.gms.location.LocationServices
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment

@ -4,6 +4,8 @@ import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.res.Configuration.ORIENTATION_PORTRAIT
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Preferences
object WidgetHelper {
class WidgetSizeProvider(
@ -51,4 +53,11 @@ object WidgetHelper {
width to second * factor
}
}
fun showSpecialWeather(context: Context): Boolean {
return EventRepository(context).getEventsCount() == 0 && (
(Preferences.showNextAlarm && AlarmHelper.getNextAlarm(context) != "") ||
(MediaPlayerHelper.isSomeonePlaying(context))
)
}
}

@ -0,0 +1,37 @@
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)
}
}

@ -8,13 +8,14 @@ import com.tommasoberlose.anotherwidget.ui.fragments.*
class ViewPagerAdapter(fragmentActivity: FragmentActivity) :
FragmentStateAdapter(fragmentActivity) {
override fun getItemCount(): Int = 4
override fun getItemCount(): Int = 5
override fun createFragment(position: Int): Fragment {
return when (position) {
1 -> CalendarTabFragment.newInstance()
2 -> WeatherTabFragment.newInstance()
3 -> ClockTabFragment.newInstance()
4 -> AtAGlanceTabFragment.newInstance()
else -> GeneralTabFragment.newInstance()
}
}

@ -0,0 +1,165 @@
package com.tommasoberlose.anotherwidget.ui.fragments
import android.app.AlarmManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.app.NotificationManagerCompat
import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
import com.tommasoberlose.anotherwidget.databinding.FragmentAtAGlanceSettingsBinding
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
import kotlinx.android.synthetic.main.fragment_at_a_glance_settings.*
import kotlinx.android.synthetic.main.fragment_at_a_glance_settings.scrollView
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.lang.Exception
class AtAGlanceTabFragment : Fragment() {
companion object {
fun newInstance() = AtAGlanceTabFragment()
}
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
val binding = DataBindingUtil.inflate<FragmentAtAGlanceSettingsBinding>(inflater, R.layout.fragment_at_a_glance_settings, container, false)
subscribeUi(binding, viewModel)
binding.lifecycleOwner = this
binding.viewModel = viewModel
return binding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setupListener()
updateNextAlarmWarningUi()
}
private fun subscribeUi(
binding: FragmentAtAGlanceSettingsBinding,
viewModel: MainViewModel
) {
viewModel.showMusic.observe(viewLifecycleOwner, Observer {
checkNotificationPermission()
})
viewModel.showNextAlarm.observe(viewLifecycleOwner, Observer {
updateNextAlarmWarningUi()
})
}
private fun setupListener() {
action_show_music.setOnClickListener {
Preferences.showMusic = !Preferences.showMusic
}
action_show_next_alarm.setOnClickListener {
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()
}
}
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 {
maintainScrollPosition {
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() {
override fun onReceive(context: Context?, intent: Intent?) {
updateNextAlarmWarningUi()
}
}
override fun onStart() {
super.onStart()
activity?.registerReceiver(nextAlarmChangeBroadcastReceiver, IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED))
}
override fun onStop() {
activity?.unregisterReceiver(nextAlarmChangeBroadcastReceiver)
super.onStop()
}
private fun checkNotificationPermission() {
if (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_show_music_enabled_subtitle) else getString(R.string.settings_show_music_disabled_subtitle)
} else if (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_show_music_disabled_subtitle)
notification_permission_alert?.isVisible = false
}
}
private fun maintainScrollPosition(callback: () -> Unit) {
val scrollPosition = scrollView.scrollY
callback.invoke()
lifecycleScope.launch {
delay(200)
scrollView.smoothScrollTo(0, scrollPosition)
}
}
override fun onResume() {
super.onResume()
checkNotificationPermission()
}
}

@ -79,7 +79,6 @@ class ClockTabFragment : Fragment() {
}
}
setupListener()
updateNextAlarmWarningUi()
}
private fun subscribeUi(
@ -138,10 +137,6 @@ class ClockTabFragment : Fragment() {
}
})
viewModel.showNextAlarm.observe(viewLifecycleOwner, Observer {
updateNextAlarmWarningUi()
})
viewModel.clockAppName.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
clock_app_label?.text =
@ -204,50 +199,6 @@ class ClockTabFragment : Fragment() {
)
}
}
action_show_next_alarm.setOnClickListener {
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()
}
}
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 {
maintainScrollPosition {
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() {
override fun onReceive(context: Context?, intent: Intent?) {
updateNextAlarmWarningUi()
}
}
override fun onStart() {
super.onStart()
activity?.registerReceiver(nextAlarmChangeBroadcastReceiver, IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED))
}
override fun onStop() {
activity?.unregisterReceiver(nextAlarmChangeBroadcastReceiver)
super.onStop()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

@ -15,6 +15,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
import androidx.core.animation.addListener
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
@ -84,6 +85,7 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
1 -> getString(R.string.settings_calendar_title)
2 -> getString(R.string.settings_weather_title)
3 -> getString(R.string.settings_clock_title)
4 -> getString(R.string.settings_at_a_glance_title)
else -> ""
}
}.attach()
@ -261,18 +263,7 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
}.start()
}
// Calendar error indicator
tabs?.getTabAt(1)?.orCreateBadge?.apply {
backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText)
badgeGravity = BadgeDrawable.TOP_END
}?.isVisible = Preferences.showEvents && activity?.checkGrantedPermission(Manifest.permission.READ_CALENDAR) != true
// Weather error indicator
tabs?.getTabAt(2)?.orCreateBadge?.apply {
backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText)
badgeGravity = BadgeDrawable.TOP_END
}?.isVisible = Preferences.showWeather && (Preferences.weatherProviderApi == "" || (Preferences.customLocationAdd == "" && activity?.checkGrantedPermission(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION) != true))
showErrorBadge()
}
@ -301,8 +292,25 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
}
}
override fun onDestroy() {
super.onDestroy()
private fun showErrorBadge() {
// Calendar error indicator
tabs?.getTabAt(1)?.orCreateBadge?.apply {
backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText)
badgeGravity = BadgeDrawable.TOP_END
}?.isVisible = Preferences.showEvents && activity?.checkGrantedPermission(Manifest.permission.READ_CALENDAR) != true
// Weather error indicator
tabs?.getTabAt(2)?.orCreateBadge?.apply {
backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText)
badgeGravity = BadgeDrawable.TOP_END
}?.isVisible = Preferences.showWeather && (Preferences.weatherProviderApi == "" || (Preferences.customLocationAdd == "" && activity?.checkGrantedPermission(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION) != true))
// Music error indicator
tabs?.getTabAt(4)?.orCreateBadge?.apply {
backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText)
badgeGravity = BadgeDrawable.TOP_END
}?.isVisible = Preferences.showMusic && !NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName)
}
override fun onSharedPreferenceChanged(preferences: SharedPreferences, p1: String) {
@ -314,6 +322,7 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
super.onResume()
Preferences.preferences.registerOnSharedPreferenceChangeListener(this)
EventBus.getDefault().register(this)
showErrorBadge()
}
override fun onPause() {

@ -30,6 +30,7 @@ import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.activities.SupportDevActivity
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import com.tommasoberlose.anotherwidget.utils.openURI
@ -195,6 +196,7 @@ class SettingsFragment : Fragment() {
action_refresh_widget.setOnClickListener {
WeatherHelper.updateWeather(requireContext())
CalendarHelper.updateEventList(requireContext())
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
}
}

@ -52,6 +52,10 @@ class MainViewModel : ViewModel() {
val showWeatherWarning = Preferences.asLiveData(Preferences::showWeatherWarning)
// Music
val showMusic = Preferences.asLiveData(Preferences::showMusic)
val mediaInfoFormat = Preferences.asLiveData(Preferences::mediaInfoFormat)
// Advanced Settings
val darkThemePreference = Preferences.asLiveData(Preferences::darkThemePreference)
val showWallpaper = Preferences.asLiveData(Preferences::showWallpaper)

@ -12,6 +12,7 @@ import android.graphics.Color
import android.graphics.Typeface
import android.os.Bundle
import android.text.format.DateUtils
import android.util.Log
import android.util.TypedValue
import android.view.View
import android.widget.ImageView
@ -52,6 +53,7 @@ class MainWidget : AppWidgetProvider() {
override fun onEnabled(context: Context) {
CalendarHelper.updateEventList(context)
WeatherReceiver.setUpdates(context)
MediaPlayerHelper.updatePlayingMediaInfo(context)
if (Preferences.showEvents) {
CalendarHelper.setEventUpdatesAndroidN(context)
@ -147,6 +149,7 @@ class MainWidget : AppWidgetProvider() {
views.setViewVisibility(R.id.empty_layout_rect, View.VISIBLE)
views.setViewVisibility(R.id.calendar_layout_rect, View.GONE)
views.setViewVisibility(R.id.second_row_rect, View.GONE)
views.setViewVisibility(R.id.next_event_difference_time_rect, View.GONE)
val calPIntent = PendingIntent.getActivity(
context,
@ -278,6 +281,29 @@ class MainWidget : AppWidgetProvider() {
)
views.setViewVisibility(R.id.second_row_rect, View.VISIBLE)
views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
views.setOnClickPendingIntent(R.id.next_event_rect, calPIntent)
} else if (MediaPlayerHelper.isSomeonePlaying(context)) {
val musicIntent = PendingIntent.getActivity(
context,
widgetID,
IntentHelper.getMusicIntent(context),
0
)
views.setOnClickPendingIntent(R.id.second_row_rect, musicIntent)
views.setImageViewBitmap(
R.id.next_event_rect,
BitmapHelper.getBitmapFromView(v.next_event, draw = false)
)
views.setImageViewBitmap(
R.id.second_row_rect,
BitmapHelper.getBitmapFromView(v.second_row, draw = false)
)
views.setViewVisibility(R.id.second_row_rect, View.VISIBLE)
views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
views.setOnClickPendingIntent(R.id.next_event_rect, calPIntent)
@ -295,6 +321,7 @@ class MainWidget : AppWidgetProvider() {
if (Preferences.showWeather && Preferences.weatherIcon != "") {
views.setViewVisibility(R.id.weather_rect, View.VISIBLE)
views.setViewVisibility(R.id.calendar_weather_rect, View.VISIBLE)
views.setViewVisibility(R.id.special_weather_rect, View.VISIBLE)
val i = Intent(context, WidgetClickListenerReceiver::class.java)
i.action = Actions.ACTION_OPEN_WEATHER_INTENT
@ -302,6 +329,7 @@ class MainWidget : AppWidgetProvider() {
views.setOnClickPendingIntent(R.id.weather_rect, weatherPIntent)
views.setOnClickPendingIntent(R.id.calendar_weather_rect, weatherPIntent)
views.setOnClickPendingIntent(R.id.special_weather_rect, weatherPIntent)
views.setImageViewBitmap(
R.id.weather_rect,
@ -312,9 +340,21 @@ class MainWidget : AppWidgetProvider() {
R.id.calendar_weather_rect,
BitmapHelper.getBitmapFromView(v.calendar_weather, draw = false)
)
views.setImageViewBitmap(
R.id.special_weather_rect,
BitmapHelper.getBitmapFromView(v.calendar_weather, draw = false)
)
if (WidgetHelper.showSpecialWeather(context)) {
views.setViewVisibility(R.id.calendar_weather_rect, View.GONE)
} else {
views.setViewVisibility(R.id.special_weather_rect, View.GONE)
}
} else {
views.setViewVisibility(R.id.weather_rect, View.GONE)
views.setViewVisibility(R.id.calendar_weather_rect, View.GONE)
views.setViewVisibility(R.id.special_weather_rect, View.GONE)
}
} catch (ex: Exception) {
ex.printStackTrace()
@ -391,6 +431,7 @@ class MainWidget : AppWidgetProvider() {
v.empty_layout.visibility = View.VISIBLE
v.calendar_layout.visibility = View.GONE
v.next_event_difference_time.visibility = View.GONE
v.action_next.isVisible = false
v.action_previous.isVisible = false
@ -469,11 +510,22 @@ class MainWidget : AppWidgetProvider() {
v.next_event_date.text = AlarmHelper.getNextAlarm(context)
v.empty_layout.visibility = View.GONE
v.calendar_layout.visibility = View.VISIBLE
} else if (MediaPlayerHelper.isSomeonePlaying(context)) {
v.second_row_icon.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.round_music_note
)
)
v.next_event.text = DateHelper.getDateText(context, now)
v.next_event_date.text = MediaPlayerHelper.getMediaInfo()
v.empty_layout.visibility = View.GONE
v.calendar_layout.visibility = View.VISIBLE
}
// Color
listOf<TextView>(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.next_event_date, v.divider2, v.calendar_temp).forEach {
listOf<TextView>(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.next_event_date, v.divider2, v.calendar_temp, v.divider3, v.special_temp).forEach {
it.setTextColor(ColorHelper.getFontColor())
}
@ -484,13 +536,15 @@ class MainWidget : AppWidgetProvider() {
// Text Size
listOf<Pair<TextView, Float>>(
v.empty_date to Preferences.textMainSize,
v.divider1 to Preferences.textMainSize,
v.divider1 to (Preferences.textMainSize - 2),
v.temp to Preferences.textMainSize,
v.next_event to Preferences.textMainSize,
v.next_event_difference_time to Preferences.textMainSize,
v.next_event_date to Preferences.textSecondSize,
v.divider2 to Preferences.textSecondSize,
v.calendar_temp to Preferences.textSecondSize
v.divider2 to (Preferences.textSecondSize - 2),
v.calendar_temp to Preferences.textSecondSize,
v.divider3 to (Preferences.textMainSize - 2),
v.special_temp to Preferences.textMainSize
).forEach {
it.first.setTextSize(TypedValue.COMPLEX_UNIT_SP, it.second)
}
@ -511,6 +565,9 @@ class MainWidget : AppWidgetProvider() {
v.action_previous.scaleX = Preferences.textMainSize / 28f
v.action_previous.scaleY = Preferences.textMainSize / 28f
v.special_weather_icon.scaleX = Preferences.textMainSize / 20f
v.special_weather_icon.scaleY = Preferences.textMainSize / 20f
// Shadows
val shadowRadius = when (Preferences.textShadow) {
@ -532,14 +589,14 @@ class MainWidget : AppWidgetProvider() {
else -> 0f
}
listOf<TextView>(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.next_event_date, v.divider2, v.calendar_temp).forEach {
listOf<TextView>(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.next_event_date, v.divider2, v.calendar_temp, v.divider3, v.special_temp).forEach {
it.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
}
// Custom Font
if (Preferences.customFont == Constants.CUSTOM_FONT_PRODUCT_SANS) {
val productSans: Typeface = Typeface.createFromAsset(context.assets, "fonts/product_sans_regular.ttf")
listOf<TextView>(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.next_event_date, v.divider2, v.calendar_temp).forEach {
listOf<TextView>(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.next_event_date, v.divider2, v.calendar_temp, v.divider3, v.special_temp).forEach {
it.typeface = productSans
}
}
@ -548,24 +605,36 @@ class MainWidget : AppWidgetProvider() {
if (Preferences.showWeather && Preferences.weatherIcon != "") {
v.weather.visibility = View.VISIBLE
v.calendar_weather.visibility = View.VISIBLE
v.special_weather.visibility = View.VISIBLE
val currentTemp = String.format(Locale.getDefault(), "%.0f °%s", Preferences.weatherTemp, Preferences.weatherRealTempUnit)
val icon: String = Preferences.weatherIcon
if (icon == "") {
v.weather_icon.visibility = View.GONE
v.empty_weather_icon.visibility = View.GONE
v.special_weather_icon.visibility = View.GONE
} else {
v.weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(icon))
v.empty_weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(icon))
v.special_weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(icon))
v.weather_icon.visibility = View.VISIBLE
v.empty_weather_icon.visibility = View.VISIBLE
v.special_weather_icon.visibility = View.VISIBLE
}
v.temp.text = currentTemp
v.calendar_temp.text = currentTemp
v.special_temp.text = currentTemp
if (WidgetHelper.showSpecialWeather(context)) {
v.calendar_weather.visibility = View.GONE
} else {
v.special_weather.visibility = View.GONE
}
} else {
v.weather.visibility = View.GONE
v.calendar_weather.visibility = View.GONE
v.special_weather.visibility = View.GONE
}
return v

Binary file not shown.

After

(image error) Size: 405 B

Binary file not shown.

After

(image error) Size: 218 B

Binary file not shown.

After

(image error) Size: 248 B

Binary file not shown.

After

(image error) Size: 338 B

Binary file not shown.

After

(image error) Size: 360 B

Binary file not shown.

After

(image error) Size: 254 B

Binary file not shown.

After

(image error) Size: 257 B

Binary file not shown.

After

(image error) Size: 412 B

Binary file not shown.

After

(image error) Size: 286 B

Binary file not shown.

After

(image error) Size: 175 B

Binary file not shown.

After

(image error) Size: 181 B

Binary file not shown.

After

(image error) Size: 248 B

Binary file not shown.

After

(image error) Size: 257 B

Binary file not shown.

After

(image error) Size: 168 B

Binary file not shown.

After

(image error) Size: 165 B

Binary file not shown.

After

(image error) Size: 283 B

Binary file not shown.

After

(image error) Size: 525 B

Binary file not shown.

After

(image error) Size: 248 B

Binary file not shown.

After

(image error) Size: 286 B

Binary file not shown.

After

(image error) Size: 405 B

Binary file not shown.

After

(image error) Size: 412 B

Binary file not shown.

After

(image error) Size: 257 B

Binary file not shown.

After

(image error) Size: 283 B

Binary file not shown.

After

(image error) Size: 507 B

Binary file not shown.

After

(image error) Size: 774 B

Binary file not shown.

After

(image error) Size: 338 B

Binary file not shown.

After

(image error) Size: 405 B

Binary file not shown.

After

(image error) Size: 588 B

Binary file not shown.

After

(image error) Size: 618 B

Binary file not shown.

After

(image error) Size: 360 B

Binary file not shown.

After

(image error) Size: 412 B

Binary file not shown.

After

(image error) Size: 789 B

Binary file not shown.

After

(image error) Size: 943 B

Binary file not shown.

After

(image error) Size: 405 B

Binary file not shown.

After

(image error) Size: 525 B

Binary file not shown.

After

(image error) Size: 774 B

Binary file not shown.

After

(image error) Size: 789 B

Binary file not shown.

After

(image error) Size: 412 B

Binary file not shown.

After

(image error) Size: 507 B

Binary file not shown.

After

(image error) Size: 982 B

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,5v8.55c-0.94,-0.54 -2.1,-0.75 -3.33,-0.32 -1.34,0.48 -2.37,1.67 -2.61,3.07 -0.46,2.74 1.86,5.08 4.59,4.65 1.96,-0.31 3.35,-2.11 3.35,-4.1V7h2c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2h-2c-1.1,0 -2,0.9 -2,2z"/>
</vector>

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M14,6L4,6c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM14,10L4,10c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM4,16h6c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1L4,14c-0.55,0 -1,0.45 -1,1s0.45,1 1,1zM19,6c-1.1,0 -2,0.9 -2,2v6.18c-0.31,-0.11 -0.65,-0.18 -1,-0.18 -1.84,0 -3.28,1.64 -2.95,3.54 0.21,1.21 1.2,2.2 2.41,2.41 1.9,0.33 3.54,-1.11 3.54,-2.95L19,8h2c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-2z"/>
</vector>

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel" />
</data>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/scrollView"
android:scrollbarThumbVertical="@color/colorPrimary"
android:background="@color/colorPrimaryDark">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:id="@+id/action_show_music"
android:orientation="horizontal">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:src="@drawable/round_music_note"
android:tint="@color/colorPrimaryText"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Settings.Title"
android:text="@string/settings_show_music_title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/show_music_label"
android:text="@string/settings_show_music_enabled_subtitle"
style="@style/AnotherWidget.Settings.Subtitle"/>
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="36dp"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:letterSpacing="0"
android:textAllCaps="false"
android:clickable="true"
android:layout_marginStart="-8dp"
android:layout_marginBottom="-8dp"
android:paddingBottom="0dp"
android:paddingTop="0dp"
android:focusable="true"
android:visibility="gone"
android:id="@+id/notification_permission_alert"
android:textColor="@color/errorColorText"
android:text="@string/action_grant_permission"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:id="@+id/action_show_next_alarm"
android:orientation="horizontal">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:src="@drawable/round_alarm"
android:tint="@color/colorPrimaryText"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Settings.Title"
android:text="@string/settings_show_next_alarm_title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/show_next_alarm_label"
style="@style/AnotherWidget.Settings.Subtitle"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Settings.Title"
android:textSize="14sp"
android:visibility="gone"
android:id="@+id/show_next_alarm_warning"
android:textColor="@color/warningColorText" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
</layout>

@ -253,51 +253,6 @@
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:id="@+id/action_show_next_alarm"
android:orientation="horizontal">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:src="@drawable/round_alarm"
android:tint="@color/colorPrimaryText"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Settings.Title"
android:text="@string/settings_show_next_alarm_title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/show_next_alarm_label"
style="@style/AnotherWidget.Settings.Subtitle"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Settings.Title"
android:textSize="14sp"
android:visibility="gone"
android:id="@+id/show_next_alarm_warning"
android:textColor="@color/warningColorText" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

@ -102,6 +102,36 @@
android:layout_gravity="center_vertical"
android:id="@+id/action_next"
android:src="@drawable/round_chevron_right" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:visibility="gone"
android:id="@+id/special_weather">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:id="@+id/divider3"
android:text="@string/divider"
android:includeFontPadding="false"
style="@style/AnotherWidget.Subtitle"/>
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:id="@+id/special_weather_icon"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Date.Big"
android:maxLines="1"
android:includeFontPadding="false"
android:id="@+id/special_temp"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"

@ -129,6 +129,10 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:id="@+id/action_next_rect" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/special_weather_rect" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"

@ -208,4 +208,11 @@
<string name="next_alarm_warning">The next alarm clock seems to be wrong.\nIt has been set by %s.</string>
<string name="settings_title">Settings</string>
<string name="settings_clock_text_color_title">Clock text color</string>
<string name="settings_music_title">Music</string>
<string name="settings_show_music_title">Show current playing song</string>
<string name="settings_show_music_enabled_subtitle">Playing song info visible</string>
<string name="settings_show_music_disabled_subtitle">Playing song info hidden</string>
<string name="settings_song_info_format_title">Song info format</string>
<string name="settings_request_notification_access">We need the notification access permission to check the current playing song.</string>
<string name="settings_at_a_glance_title">At a Glance</string>
</resources>

@ -188,4 +188,11 @@
<string name="next_alarm_warning">The next alarm clock seems to be wrong.\nIt has been set by %s.</string>
<string name="settings_title">Settings</string>
<string name="settings_clock_text_color_title">Clock text color</string>
<string name="settings_music_title">Music</string>
<string name="settings_show_music_title">Show current playing song</string>
<string name="settings_show_music_enabled_subtitle">Playing song info visible</string>
<string name="settings_show_music_disabled_subtitle">Playing song info hidden</string>
<string name="settings_song_info_format_title">Song info format</string>
<string name="settings_request_notification_access">We need the notification access permission to check the current playing song.</string>
<string name="settings_at_a_glance_title">At a Glance</string>
</resources>

@ -187,4 +187,11 @@
<string name="next_alarm_warning">La sveglia sembra impostata male.\nÈ stata impostata dall\'app %s.</string>
<string name="settings_title">Impostazioni</string>
<string name="settings_clock_text_color_title">Colore orologio</string>
<string name="settings_music_title">Musica</string>
<string name="settings_show_music_title">Mostra brano in riproduzione</string>
<string name="settings_show_music_enabled_subtitle">Visibile</string>
<string name="settings_show_music_disabled_subtitle">Non visibile</string>
<string name="settings_song_info_format_title">Formato informazioni brano</string>
<string name="settings_request_notification_access">Concedi all\'app il permesso di monitorare le notifiche, è necessario per poter mostrare il brano in riproduzione.</string>
<string name="settings_at_a_glance_title">At a Glance</string>
</resources>

@ -199,4 +199,11 @@
<string name="next_alarm_warning">The next alarm clock seems to be wrong.\nIt has been set by %s.</string>
<string name="settings_title">Settings</string>
<string name="settings_clock_text_color_title">Clock text color</string>
<string name="settings_at_a_glance_title">At a Glance</string>
<string name="settings_music_title">Music</string>
<string name="settings_show_music_title">Show current playing song</string>
<string name="settings_show_music_enabled_subtitle">Playing song info visible</string>
<string name="settings_show_music_disabled_subtitle">Playing song info hidden</string>
<string name="settings_song_info_format_title">Song info format</string>
<string name="settings_request_notification_access">We need the notification access permission to check the current playing song.</string>
</resources>

@ -3,8 +3,8 @@
xmlns:dist="http://schemas.android.com/apk/distribution"
featureSplit="tasksintegration"
package="com.tommasoberlose.anotherwidget"
android:versionCode="78"
android:versionName="2.0.5" >
android:versionCode="80"
android:versionName="2.0.6" >
<uses-sdk
android:minSdkVersion="23"

@ -1,4 +1,4 @@
#Fri May 08 15:13:22 CEST 2020
#Fri May 08 18:14:21 CEST 2020
base.0=/Users/tommaso/Documents/MyCode/another-widget/tasksintegration/build/intermediates/dex/debug/mergeProjectDexDebug/out/classes.dex
path.0=classes.dex
renamed.0=classes.dex

@ -4,8 +4,8 @@
featureSplit="tasksintegration"
package="com.tommasoberlose.anotherwidget"
android:targetSandboxVersion="2"
android:versionCode="78"
android:versionName="2.0.5" >
android:versionCode="80"
android:versionName="2.0.6" >
<uses-sdk
android:minSdkVersion="23"

@ -3,8 +3,8 @@
3 xmlns:dist="http://schemas.android.com/apk/distribution"
4 featureSplit="tasksintegration"
5 package="com.tommasoberlose.anotherwidget"
6 android:versionCode="78"
7 android:versionName="2.0.5" >
6 android:versionCode="80"
7 android:versionName="2.0.6" >
8
9 <uses-sdk
10 android:minSdkVersion="23"

@ -3,8 +3,8 @@
xmlns:dist="http://schemas.android.com/apk/distribution"
featureSplit="tasksintegration"
package="com.tommasoberlose.anotherwidget"
android:versionCode="78"
android:versionName="2.0.5" >
android:versionCode="80"
android:versionName="2.0.6" >
<uses-sdk
android:minSdkVersion="23"

@ -3,8 +3,8 @@
xmlns:dist="http://schemas.android.com/apk/distribution"
featureSplit="tasksintegration"
package="com.tommasoberlose.anotherwidget"
android:versionCode="78"
android:versionName="2.0.5" >
android:versionCode="80"
android:versionName="2.0.6" >
<uses-sdk android:targetSdkVersion="29" />