Material components date and time pickers

pull/1415/head
Alex Baker 3 years ago
parent 4e1b496c4b
commit 40d831f7da

@ -216,7 +216,6 @@ dependencies {
implementation("com.rubiconproject.oss:jchronic:0.2.6") {
isTransitive = false
}
implementation("com.wdullaer:materialdatetimepicker:4.2.3")
implementation("me.leolin:ShortcutBadger:1.1.22@aar")
implementation("com.google.apis:google-api-services-tasks:v1-rev20210109-1.31.0")
implementation("com.google.apis:google-api-services-drive:v3-rev20210228-1.31.0")

@ -159,12 +159,6 @@
license: The Apache Software License, Version 2.0
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
url: https://github.com/JetBrains/java-annotations
- artifact: com.wdullaer:materialdatetimepicker:+
name: MaterialDateTimePicker
copyrightHolder: Wouter Dullaert
license: The Apache Software License, Version 2.0
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
url: https://github.com/wdullaer/MaterialDateTimePicker
- artifact: org.apache.commons:commons-lang3:+
name: Apache Commons Lang
copyrightHolder: The Apache Software Foundation

@ -385,20 +385,6 @@
"url": "https://github.com/JetBrains/java-annotations",
"libraryName": "JetBrains Java Annotations"
},
{
"artifactId": {
"name": "materialdatetimepicker",
"group": "com.wdullaer",
"version": "+"
},
"copyrightHolder": "Wouter Dullaert",
"copyrightStatement": "Copyright © Wouter Dullaert. All rights reserved.",
"license": "The Apache Software License, Version 2.0",
"licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt",
"normalizedLicense": "apache2",
"url": "https://github.com/wdullaer/MaterialDateTimePicker",
"libraryName": "MaterialDateTimePicker"
},
{
"artifactId": {
"name": "commons-lang3",

@ -1,85 +0,0 @@
package org.tasks.activities;
import static org.tasks.dialogs.MyDatePickerDialog.newDatePicker;
import static org.tasks.dialogs.MyTimePickerDialog.newTimePicker;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import dagger.hilt.android.AndroidEntryPoint;
import javax.inject.Inject;
import org.tasks.dialogs.MyDatePickerDialog;
import org.tasks.dialogs.MyTimePickerDialog;
import org.tasks.injection.InjectingAppCompatActivity;
import org.tasks.preferences.Preferences;
import org.tasks.themes.ThemeAccent;
import org.tasks.time.DateTime;
@AndroidEntryPoint
public class DateAndTimePickerActivity extends InjectingAppCompatActivity
implements MyDatePickerDialog.DatePickerCallback, MyTimePickerDialog.TimePickerCallback {
public static final String EXTRA_TIMESTAMP = "extra_timestamp";
private static final String FRAG_TAG_DATE_PICKER = "frag_tag_date_picker";
private static final String FRAG_TAG_TIME_PICKER = "frag_tag_time_picker";
private static final String EXTRA_DATE_SELECTED = "extra_date_selected";
@Inject ThemeAccent themeAccent;
@Inject Preferences preferences;
private DateTime initial;
private boolean dateSelected;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initial = new DateTime(getIntent().getLongExtra(EXTRA_TIMESTAMP, currentTimeMillis()));
if (savedInstanceState != null) {
dateSelected = savedInstanceState.getBoolean(EXTRA_DATE_SELECTED, false);
if (dateSelected) {
return;
}
}
themeAccent.applyStyle(getTheme());
androidx.fragment.app.FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.findFragmentByTag(FRAG_TAG_DATE_PICKER) == null) {
newDatePicker(null, 0, initial.getMillis())
.show(getSupportFragmentManager(), FRAG_TAG_DATE_PICKER);
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(EXTRA_DATE_SELECTED, dateSelected);
}
@Override
public void onDatePicked(DialogInterface dialog, long timestamp) {
if (timestamp == MyDatePickerDialog.NO_DATE) {
finish();
} else {
dialog.dismiss();
dateSelected = true;
newTimePicker(
null,
0,
new DateTime(timestamp).withMillisOfDay(initial.getMillisOfDay()).getMillis())
.show(getSupportFragmentManager(), FRAG_TAG_TIME_PICKER);
}
}
@Override
public void onTimePicked(long timestamp) {
if (timestamp != MyTimePickerDialog.NO_TIME) {
final Intent data = new Intent();
data.putExtra(MyTimePickerDialog.EXTRA_TIMESTAMP, timestamp);
setResult(RESULT_OK, data);
}
finish();
}
}

@ -0,0 +1,106 @@
package org.tasks.activities
import android.content.Intent
import android.os.Bundle
import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.timepicker.MaterialTimePicker
import dagger.hilt.android.AndroidEntryPoint
import org.tasks.dialogs.MyDatePickerDialog.Companion.newDatePicker
import org.tasks.dialogs.MyTimePickerDialog
import org.tasks.dialogs.MyTimePickerDialog.Companion.newTimePicker
import org.tasks.injection.InjectingAppCompatActivity
import org.tasks.preferences.Preferences
import org.tasks.themes.ThemeAccent
import org.tasks.time.DateTime
import org.tasks.time.DateTimeUtils.currentTimeMillis
import javax.inject.Inject
@AndroidEntryPoint
class DateAndTimePickerActivity : InjectingAppCompatActivity() {
@Inject lateinit var themeAccent: ThemeAccent
@Inject lateinit var preferences: Preferences
private var initial: DateTime? = null
private var dateSelected: DateTime? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initial = DateTime(intent.getLongExtra(EXTRA_TIMESTAMP, currentTimeMillis()))
dateSelected =
savedInstanceState
?.getLong(EXTRA_DATE_SELECTED)
?.takeIf { it > 0 }
?.let { DateTime(it, DateTime.UTC) }
themeAccent.applyStyle(theme)
if (dateSelected != null) {
showTimePicker()
} else {
showDatePicker(initial ?: DateTime())
}
}
private fun showDatePicker(date: DateTime) {
dateSelected = null
val picker =
supportFragmentManager
.findFragmentByTag(FRAG_TAG_DATE_PICKER) as? MaterialDatePicker<Long>
?: newDatePicker(date.millis).apply {
show(supportFragmentManager, FRAG_TAG_DATE_PICKER)
}
picker.apply {
addOnPositiveButtonClickListener {
dateSelected = DateTime(selection!!, DateTime.UTC)
showTimePicker()
}
addOnCancelListener { finish() }
addOnNegativeButtonClickListener { finish() }
}
}
private fun showTimePicker() {
val fragmentManager = supportFragmentManager
val picker =
fragmentManager
.findFragmentByTag(FRAG_TAG_TIME_PICKER) as? MaterialTimePicker
?: newTimePicker(
this,
DateTime(dateSelected!!.year, dateSelected!!.monthOfYear, dateSelected!!.dayOfMonth)
.withMillisOfDay(initial!!.millisOfDay).millis
).apply { show(fragmentManager, FRAG_TAG_TIME_PICKER) }
picker.apply {
addOnCancelListener {
dateSelected?.let { showDatePicker(it) } ?: finish()
}
addOnNegativeButtonClickListener {
dateSelected?.let { showDatePicker(it) } ?: finish()
}
addOnPositiveButtonClickListener {
val data = Intent()
data.putExtra(
MyTimePickerDialog.EXTRA_TIMESTAMP,
DateTime(
dateSelected!!.year,
dateSelected!!.monthOfYear,
dateSelected!!.dayOfMonth,
hour,
minute
).millis
)
setResult(RESULT_OK, data)
finish()
}
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
dateSelected?.let { outState.putLong(EXTRA_DATE_SELECTED, it.millis) }
}
companion object {
const val EXTRA_TIMESTAMP = "extra_timestamp"
private const val FRAG_TAG_DATE_PICKER = "frag_tag_date_picker"
private const val FRAG_TAG_TIME_PICKER = "frag_tag_time_picker"
private const val EXTRA_DATE_SELECTED = "extra_date_selected"
}
}

@ -21,7 +21,7 @@ import org.tasks.R
import org.tasks.databinding.DialogDateTimePickerBinding
import org.tasks.date.DateTimeUtils.newDateTime
import org.tasks.date.DateTimeUtils.toDateTime
import org.tasks.dialogs.MyTimePickerDialog.newTimePicker
import org.tasks.dialogs.MyTimePickerDialog.Companion.newTimePicker
import org.tasks.locale.Locale
import org.tasks.notifications.NotificationManager
import org.tasks.time.DateTime

@ -1,93 +0,0 @@
package org.tasks.dialogs;
import static android.app.Activity.RESULT_CANCELED;
import static android.app.Activity.RESULT_OK;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog;
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog.OnDateSetListener;
import org.tasks.R;
import org.tasks.preferences.Preferences;
import org.tasks.time.DateTime;
public class MyDatePickerDialog extends DatePickerDialog implements OnDateSetListener {
public static final String EXTRA_TIMESTAMP = "extra_timestamp";
public static final int NO_DATE = -1;
public static MyDatePickerDialog newDatePicker(Fragment target, int rc, long initial) {
Bundle arguments = new Bundle();
arguments.putLong(EXTRA_TIMESTAMP, initial);
MyDatePickerDialog dialog = new MyDatePickerDialog();
dialog.setArguments(arguments);
dialog.setTargetFragment(target, rc);
return dialog;
}
public interface DatePickerCallback{ // TODO: remove this after removing DateAndTimePickerActivity
void onDatePicked(DialogInterface dialog, long timestamp);
}
private DatePickerCallback callback;
@Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState == null) {
long timestamp = getArguments().getLong(EXTRA_TIMESTAMP, currentTimeMillis());
DateTime initial = (timestamp > 0 ? new DateTime(timestamp) : new DateTime()).startOfDay();
initialize(
null,
initial.getYear(),
initial.getMonthOfYear() - 1,
initial.getDayOfMonth());
setVersion(DatePickerDialog.Version.VERSION_2);
int firstDayOfWeek = new Preferences(getContext()).getFirstDayOfWeek();
if (firstDayOfWeek >= 1 && firstDayOfWeek <= 7) {
setFirstDayOfWeek(firstDayOfWeek);
}
setThemeDark(getResources().getBoolean(R.bool.is_dark)); // TODO: remove this after removing DateAndTimePickerActivity
}
setOnDateSetListener(this);
super.onCreate(savedInstanceState);
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof DatePickerCallback) {
callback = (DatePickerCallback) context;
}
}
@Override
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
if (getTargetFragment() == null) {
callback.onDatePicked(dialog, NO_DATE);
} else {
getTargetFragment().onActivityResult(getTargetRequestCode(), RESULT_CANCELED, null);
}
}
@Override
public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) {
long result = new DateTime(year, monthOfYear + 1, dayOfMonth).getMillis();
if (getTargetFragment() == null) {
callback.onDatePicked(getDialog(), result);
} else {
Intent data = new Intent();
data.putExtra(EXTRA_TIMESTAMP, result);
getTargetFragment().onActivityResult(getTargetRequestCode(), RESULT_OK, data);
}
}
}

@ -0,0 +1,76 @@
package org.tasks.dialogs
import android.app.Activity.RESULT_CANCELED
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import com.google.android.material.datepicker.MaterialDatePicker
import com.todoroo.andlib.utility.DateUtilities
import org.tasks.time.DateTime
import org.tasks.time.DateTimeUtils.currentTimeMillis
import org.tasks.time.DateTimeUtils.startOfDay
class MyDatePickerDialog : DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val fragment =
(childFragmentManager.findFragmentByTag(FRAG_TAG_DATE_PICKER) as? MaterialDatePicker<Long>)
?: newDatePicker(initial)
.let {
childFragmentManager
.beginTransaction()
.add(it, FRAG_TAG_DATE_PICKER)
.commit()
it
}
with(fragment) {
addOnPositiveButtonClickListener {
val dt = DateTime(it, DateTime.UTC)
selected(dt.year, dt.monthOfYear, dt.dayOfMonth)
}
addOnCancelListener { cancel() }
addOnNegativeButtonClickListener { cancel() }
}
}
private val initial: Long
get() = arguments?.getLong(MyTimePickerDialog.EXTRA_TIMESTAMP) ?: DateUtilities.now().startOfDay()
private fun selected(year: Int, month: Int, day: Int) {
targetFragment?.onActivityResult(
targetRequestCode,
RESULT_OK,
Intent().putExtra(EXTRA_TIMESTAMP, DateTime(year, month, day).millis)
)
dismiss()
}
private fun cancel() {
targetFragment?.onActivityResult(targetRequestCode, RESULT_CANCELED, null)
dismiss()
}
companion object {
const val FRAG_TAG_DATE_PICKER = "frag_date_picker"
const val EXTRA_TIMESTAMP = "extra_timestamp"
@JvmStatic
fun newDatePicker(target: Fragment, rc: Int, initial: Long) =
MyDatePickerDialog().apply {
arguments = Bundle().apply {
putLong(EXTRA_TIMESTAMP, initial)
}
setTargetFragment(target, rc)
}
@JvmStatic
fun newDatePicker(initial: Long) = MaterialDatePicker.Builder.datePicker()
// TODO: setInputMode for calendar or text
// TODO: figure out hack for first day of week
.setSelection(if (initial > 0) initial else currentTimeMillis())
.build()
}
}

@ -1,91 +0,0 @@
package org.tasks.dialogs;
import static android.app.Activity.RESULT_CANCELED;
import static android.app.Activity.RESULT_OK;
import static org.tasks.date.DateTimeUtils.newDateTime;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.text.format.DateFormat;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.wdullaer.materialdatetimepicker.time.TimePickerDialog;
import com.wdullaer.materialdatetimepicker.time.TimePickerDialog.OnTimeSetListener;
import org.tasks.R;
import org.tasks.time.DateTime;
public class MyTimePickerDialog extends TimePickerDialog implements OnTimeSetListener {
public static final String EXTRA_TIMESTAMP = "extra_timestamp";
public static final int NO_TIME = -1;
public static MyTimePickerDialog newTimePicker(Fragment target, int rc, long initial) {
Bundle arguments = new Bundle();
arguments.putLong(EXTRA_TIMESTAMP, initial);
MyTimePickerDialog dialog = new MyTimePickerDialog();
dialog.setArguments(arguments);
dialog.setTargetFragment(target, rc);
return dialog;
}
public interface TimePickerCallback { // TODO: remove this after removing DateAndTimePickerActivity
void onTimePicked(long timestamp);
}
private DateTime initial;
private TimePickerCallback callback;
@Override
public void onCreate(Bundle savedInstanceState) {
initial = newDateTime(getArguments().getLong(EXTRA_TIMESTAMP, currentTimeMillis()));
if (savedInstanceState == null) {
initialize(
null,
initial.getHourOfDay(),
initial.getMinuteOfHour(),
0,
DateFormat.is24HourFormat(getContext()));
setThemeDark(getResources().getBoolean(R.bool.is_dark)); // TODO: remove this after removing DateAndTimePickerActivity
}
setOnTimeSetListener(this);
super.onCreate(savedInstanceState);
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof TimePickerCallback) {
callback = (TimePickerCallback) context;
}
}
@Override
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
if (getTargetFragment() == null) {
callback.onTimePicked(NO_TIME);
} else {
getTargetFragment().onActivityResult(getTargetRequestCode(), RESULT_CANCELED, null);
}
}
@Override
public void onTimeSet(TimePickerDialog view, int hours, int minutes, int second) {
long result = initial.startOfDay().withHourOfDay(hours).withMinuteOfHour(minutes).getMillis();
if (getTargetFragment() == null) {
callback.onTimePicked(result);
} else {
Intent data = new Intent();
data.putExtra(EXTRA_TIMESTAMP, result);
getTargetFragment().onActivityResult(getTargetRequestCode(), RESULT_OK, data);
}
}
}

@ -0,0 +1,86 @@
package org.tasks.dialogs
import android.app.Activity
import android.app.Activity.RESULT_CANCELED
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.text.format.DateFormat.is24HourFormat
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import com.google.android.material.timepicker.MaterialTimePicker
import com.google.android.material.timepicker.TimeFormat.CLOCK_12H
import com.google.android.material.timepicker.TimeFormat.CLOCK_24H
import com.todoroo.andlib.utility.DateUtilities.now
import org.tasks.date.DateTimeUtils.toDateTime
import org.tasks.time.DateTime
import org.tasks.time.DateTimeUtils.startOfDay
class MyTimePickerDialog : DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val fragment =
(childFragmentManager.findFragmentByTag(FRAG_TAG_TIME_PICKER) as? MaterialTimePicker)
?: newTimePicker(requireContext(), initial)
.let {
childFragmentManager
.beginTransaction()
.add(it, FRAG_TAG_TIME_PICKER)
.commit()
it
}
with(fragment) {
addOnPositiveButtonClickListener { selected(hour, minute) }
addOnNegativeButtonClickListener { cancel() }
addOnCancelListener { cancel() }
}
}
private val initial: Long
get() = arguments?.getLong(EXTRA_TIMESTAMP) ?: now().startOfDay()
private fun selected(hour: Int, minute: Int) {
targetFragment?.onActivityResult(
targetRequestCode,
Activity.RESULT_OK,
Intent().putExtra(
EXTRA_TIMESTAMP,
initial
.toDateTime()
.startOfDay()
.withHourOfDay(hour)
.withMinuteOfHour(minute)
.millis
)
)
dismiss()
}
private fun cancel() {
targetFragment?.onActivityResult(targetRequestCode, RESULT_CANCELED, null)
dismiss()
}
companion object {
const val FRAG_TAG_TIME_PICKER = "frag_time_picker"
const val EXTRA_TIMESTAMP = "extra_timestamp"
fun newTimePicker(target: Fragment, rc: Int, initial: Long) =
MyTimePickerDialog().apply {
arguments = Bundle().apply {
putLong(EXTRA_TIMESTAMP, initial)
}
setTargetFragment(target, rc)
}
@JvmStatic
fun newTimePicker(context: Context?, initial: Long) = DateTime(initial).let {
MaterialTimePicker.Builder()
.setTimeFormat(if (is24HourFormat(context)) CLOCK_24H else CLOCK_12H)
.setHour(it.hourOfDay)
.setMinute(it.minuteOfHour)
.build()
}
}
}

@ -17,7 +17,7 @@ import dagger.hilt.android.AndroidEntryPoint
import org.tasks.R
import org.tasks.databinding.DialogStartDatePickerBinding
import org.tasks.date.DateTimeUtils.newDateTime
import org.tasks.dialogs.MyTimePickerDialog.newTimePicker
import org.tasks.dialogs.MyTimePickerDialog.Companion.newTimePicker
import org.tasks.locale.Locale
import org.tasks.notifications.NotificationManager
import org.tasks.time.DateTime

@ -8,7 +8,7 @@ import androidx.preference.ListPreference
import androidx.preference.Preference
import dagger.hilt.android.AndroidEntryPoint
import org.tasks.R
import org.tasks.dialogs.MyTimePickerDialog.newTimePicker
import org.tasks.dialogs.MyTimePickerDialog.Companion.newTimePicker
import org.tasks.injection.InjectingPreferenceFragment
import org.tasks.locale.Locale
import org.tasks.preferences.Preferences

@ -20,7 +20,7 @@ import kotlinx.coroutines.launch
import org.tasks.LocalBroadcastManager
import org.tasks.R
import org.tasks.activities.FilterSelectionActivity
import org.tasks.dialogs.MyTimePickerDialog.newTimePicker
import org.tasks.dialogs.MyTimePickerDialog.Companion.newTimePicker
import org.tasks.injection.InjectingPreferenceFragment
import org.tasks.preferences.DefaultFilterProvider
import org.tasks.preferences.Preferences

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorOnSecondary" android:state_selected="true" />
<item android:color="?attr/colorOnSurface" />
</selector>

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2019 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 24% opacity -->
<item android:alpha="0.24" android:color="?attr/colorSecondary" android:state_enabled="true" android:state_selected="true"/>
<item android:alpha="0.24" android:color="?attr/colorSecondary" android:state_enabled="true" android:state_checked="true"/>
<!-- 12% of 87% opacity -->
<item android:alpha="0.10" android:color="?attr/colorOnSurface" android:state_enabled="true"/>
<item android:alpha="0.12" android:color="?attr/colorOnSurface"/>
</selector>

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2019 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorSecondary" android:state_enabled="true" android:state_selected="true"/>
<item android:color="?attr/colorSecondary" android:state_enabled="true" android:state_checked="true"/>
<!-- 87% opacity. -->
<item android:alpha="0.87" android:color="?attr/colorOnSurface" android:state_enabled="true"/>
<!-- 38% of 87% opacity. -->
<item android:alpha="0.33" android:color="?attr/colorOnSurface"/>
</selector>

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2018 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorSecondary" android:state_focused="true"/>
<!-- 4% overlay over 42% colorOnSurface -->
<item android:alpha="0.46" android:color="?attr/colorOnSurface" android:state_hovered="true"/>
<item android:alpha="0.38" android:color="?attr/colorOnSurface" android:state_enabled="false"/>
<item android:alpha="0.42" android:color="?attr/colorOnSurface"/>
</selector>

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="1.00" android:color="?attr/colorSecondary" android:state_checkable="true" android:state_checked="true" android:state_enabled="true"/>
<item android:alpha="0.60" android:color="?attr/colorOnSurface" android:state_checkable="true" android:state_checked="false" android:state_enabled="true"/>
<item android:alpha="1.00" android:color="?attr/colorSecondary" android:state_enabled="true"/>
<item android:alpha="0.38" android:color="?attr/colorOnSurface"/>
</selector>

@ -7,8 +7,6 @@
<string name="app_package">org.tasks</string>
<string name="opentasks_authority" tools:node="replace">org.tasks.opentasks</string>
<string name="backup_api_key">AEdPqrEAAAAI49v5bBusi_bq1bgLBB1LIsepNV0eBrFkQrBZkw</string>
<string name="mdtp_ok">@string/ok</string>
<string name="mdtp_cancel">@string/cancel</string>
<string name="FSA_label">Tasks Shortcut</string>
<string name="caldav">CalDAV</string>
<string name="etesync">EteSync</string>

@ -20,6 +20,9 @@
<item name="materialAlertDialogTheme">@style/TasksDialogAlert</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowAnimationStyle">@android:style/Animation</item>
<item name="materialTimePickerTheme">@style/ClockTheme</item>
<item name="materialCalendarTheme">@style/CalendarTheme</item>
<item name="textInputStyle">@style/OutlinedBox</item>
</style>
<style name="TaskEditTextPrimary">
@ -187,8 +190,6 @@
<item name="android:textColor">@color/overdue</item>
</style>
<style name="mdtp_ActionButton.Text" parent="Widget.MaterialComponents.Button.TextButton.Dialog.Flush"/>
<style name="AlertButtonStyle" parent="Widget.MaterialComponents.Button.TextButton.Dialog.Flush">
<item name="android:textColor">?attr/colorSecondary</item>
</style>
@ -211,4 +212,59 @@
<item name="android:scaleType">fitCenter</item>
</style>
<style name="ClockTheme" parent="ThemeOverlay.MaterialComponents.TimePicker">
<item name="materialClockStyle">@style/ClockStyle</item>
</style>
<style name="ClockStyle" parent="Widget.MaterialComponents.TimePicker.Clock">
<item name="clockHandColor">?attr/colorSecondary</item>
<item name="clockNumberTextColor">@color/clock_text_color</item>
</style>
<style name="CalendarTheme" parent="@style/ThemeOverlay.MaterialComponents.MaterialCalendar">
<item name="materialCalendarStyle">@style/CalendarStyle</item>
<item name="materialCalendarHeaderLayout">@style/CalendarHeaderLayout</item>
<item name="materialCalendarHeaderDivider">@style/CalendarHeaderDivider</item>
<item name="materialCalendarHeaderTitle">@style/CalendarHeaderTitle</item>
<item name="materialCalendarHeaderSelection">@style/CalendarHeaderSelection</item>
<item name="android:colorControlActivated">?attr/colorSecondary</item>
</style>
<style name="CalendarStyle" parent="@style/Widget.MaterialComponents.MaterialCalendar">
<item name="daySelectedStyle">@style/CalendarDaySelected</item>
<item name="yearSelectedStyle">@style/CalendarYearSelected</item>
<item name="hintTextColor">?attr/colorSecondary</item>
</style>
<style name="CalendarHeaderLayout" parent="Widget.MaterialComponents.MaterialCalendar.HeaderLayout">
<item name="android:background">?attr/colorSecondary</item>
</style>
<style name="CalendarHeaderDivider" parent="Widget.MaterialComponents.MaterialCalendar.HeaderDivider">
<item name="android:background">?attr/colorOnSecondary</item>
</style>
<style name="CalendarHeaderTitle" parent="Widget.MaterialComponents.MaterialCalendar.HeaderTitle">
<item name="android:textColor">?attr/colorOnSecondary</item>
</style>
<style name="CalendarHeaderSelection" parent="Widget.MaterialComponents.MaterialCalendar.HeaderSelection">
<item name="android:textColor">?attr/colorOnSecondary</item>
</style>
<style name="CalendarDaySelected" parent="Widget.MaterialComponents.MaterialCalendar.Day.Selected">
<item name="itemFillColor">?attr/colorSecondary</item>
<item name="itemTextColor">?attr/colorOnSecondary</item>
</style>
<style name="CalendarYearSelected" parent="Widget.MaterialComponents.MaterialCalendar.Year.Selected">
<item name="itemFillColor">?attr/colorSecondary</item>
<item name="itemTextColor">?attr/colorOnSecondary</item>
<item name="itemStrokeColor">?attr/colorOnSecondary</item>
</style>
<style name="OutlinedBox" parent="Widget.MaterialComponents.TextInputLayout.FilledBox">
<item name="boxStrokeColor">?attr/colorSecondary</item>
<item name="hintTextColor">?attr/colorSecondary</item>
</style>
</resources>

@ -21,7 +21,9 @@
<item name="android:textColorTertiary">@color/text_tertiary</item>
<item name="card_elevation">2dp</item>
<item name="horizontal_divider_visibility">2</item> <!-- View.GONE -->
<item name="mdtp_theme_dark">@bool/is_dark</item>
<item name="materialTimePickerTheme">@style/ClockTheme</item>
<item name="materialCalendarTheme">@style/CalendarTheme</item>
<item name="textInputStyle">@style/OutlinedBox</item>
</style>
<style name="Tasks" parent="TasksBase">

@ -330,9 +330,6 @@
++--- com.google.android.apps.dashclock:dashclock-api:2.0.0
++--- com.twofortyfouram:android-plugin-api-for-locale:1.0.2
++--- com.rubiconproject.oss:jchronic:0.2.6
++--- com.wdullaer:materialdatetimepicker:4.2.3
+| +--- androidx.appcompat:appcompat:1.0.2 -> 1.3.0-beta01 (*)
+| \--- androidx.recyclerview:recyclerview:1.0.0 -> 1.1.0 (*)
++--- me.leolin:ShortcutBadger:1.1.22
++--- com.google.apis:google-api-services-tasks:v1-rev20210109-1.31.0
+| \--- com.google.api-client:google-api-client:1.31.1

@ -444,9 +444,6 @@
++--- com.google.android.apps.dashclock:dashclock-api:2.0.0
++--- com.twofortyfouram:android-plugin-api-for-locale:1.0.2
++--- com.rubiconproject.oss:jchronic:0.2.6
++--- com.wdullaer:materialdatetimepicker:4.2.3
+| +--- androidx.appcompat:appcompat:1.0.2 -> 1.3.0-beta01 (*)
+| \--- androidx.recyclerview:recyclerview:1.0.0 -> 1.1.0 (*)
++--- me.leolin:ShortcutBadger:1.1.22
++--- com.google.apis:google-api-services-tasks:v1-rev20210109-1.31.0
+| \--- com.google.api-client:google-api-client:1.31.1

Loading…
Cancel
Save