mirror of https://github.com/tasks/tasks
Compare commits
358 Commits
Author | SHA1 | Date |
---|---|---|
Alex Baker | 97a3f074d0 | 1 day ago |
Alex Baker | 86ecd3cf81 | 1 day ago |
Alex Baker | 07a2eda5ea | 1 day ago |
renovate[bot] | 09ffbdd036 | 1 day ago |
renovate[bot] | 60f22146ca | 1 day ago |
renovate[bot] | c11225abaf | 1 day ago |
dependabot[bot] | 133ea493e3 | 1 day ago |
Alex Baker | 0ba901be69 | 5 days ago |
Alex Baker | ebe5e5c009 | 6 days ago |
Alex Baker | d556863fda | 6 days ago |
Alex Baker | 55adbc2025 | 6 days ago |
Alex Baker | 06c4255886 | 6 days ago |
renovate[bot] | 4734a99bae | 7 days ago |
Alex Baker | a6a8cac8e4 | 1 week ago |
Alex Baker | c3fc9a57cc | 1 week ago |
Alex Baker | 6e14d07d0c | 1 week ago |
Alex Baker | 6118121698 | 1 week ago |
Alex Baker | 6bf3bd4d08 | 1 week ago |
Alex Baker | 065be79355 | 1 week ago |
Alex Baker | f8f8ba3c51 | 1 week ago |
Alex Baker | 89465f36b3 | 1 week ago |
Alex Baker | 1380a34ffa | 1 week ago |
Alex Baker | 10af5280a3 | 1 week ago |
Alex Baker | 8c0f7b952d | 1 week ago |
Alex Baker | 65362b203f | 1 week ago |
Alex Baker | 3327f97a17 | 1 week ago |
Alex Baker | c9fc02a42e | 1 week ago |
renovate[bot] | 93670bb9e4 | 1 week ago |
Alex Baker | 1fc6a50d0b | 1 week ago |
Alex Baker | e1ef924909 | 1 week ago |
Alex Baker | 686cb5d346 | 1 week ago |
renovate[bot] | ebec25c4cb | 1 week ago |
renovate[bot] | c140f7e673 | 2 weeks ago |
renovate[bot] | efbcf11a4a | 2 weeks ago |
renovate[bot] | 6adee85a37 | 2 weeks ago |
Alex Baker | 5c8643110b | 2 weeks ago |
Alex Baker | abd13aeb75 | 2 weeks ago |
Alex Baker | c210fe1893 | 2 weeks ago |
Alex Baker | 26aa916c20 | 2 weeks ago |
renovate[bot] | 1eff2d1cd5 | 2 weeks ago |
islam2hamy | c90e683ea3 | 2 weeks ago |
Alex Baker | 3cd0295b71 | 2 weeks ago |
Alex Baker | 95c351e9fd | 2 weeks ago |
renovate[bot] | 4ddb7816f1 | 2 weeks ago |
renovate[bot] | 91c30f7bbf | 2 weeks ago |
renovate[bot] | 3f4398b6e0 | 2 weeks ago |
renovate[bot] | c822e989a3 | 2 weeks ago |
renovate[bot] | da146723e5 | 2 weeks ago |
109247019824 | 931626c84a | 2 weeks ago |
Alex Baker | c534632c52 | 2 weeks ago |
Alex Baker | c1347a7455 | 2 weeks ago |
renovate[bot] | 9544909a58 | 2 weeks ago |
Yurt Page | 5c10dce2b9 | 2 weeks ago |
Alex Baker | 584d4a5cbb | 2 weeks ago |
Alex Baker | 7c68a7fa59 | 2 weeks ago |
purushottamyadavbattula | 215cc838ef | 2 weeks ago |
Alex Baker | d60472d1bc | 3 weeks ago |
Alex Baker | f84a37a60a | 3 weeks ago |
Alex Baker | 7fb85b6da1 | 3 weeks ago |
Alex Baker | dc90e583e4 | 3 weeks ago |
Don Zouras | 0eac5f61eb | 4 weeks ago |
Milo Ivir | c686ce883d | 4 weeks ago |
大王叫我来巡山 | ab25398cd0 | 4 weeks ago |
renovate[bot] | 3b1c133d22 | 4 weeks ago |
renovate[bot] | 3bfd0ab4f8 | 4 weeks ago |
Liz de Sartiges | ffc0113d7f | 4 weeks ago |
Don Zouras | 9de9718ad5 | 4 weeks ago |
Oğuz Ersen | a7d2c9c406 | 4 weeks ago |
gallegonovato | b3006b9ac2 | 4 weeks ago |
Don Zouras | de3ef1f9c9 | 4 weeks ago |
Alex Baker | ce9e722a3f | 4 weeks ago |
Alex Baker | 4b892a0eb1 | 4 weeks ago |
Hady | e6e275834a | 4 weeks ago |
Alex Baker | 782f4d6d7c | 4 weeks ago |
elmuffo | a1da71d3e1 | 4 weeks ago |
Alex Baker | c793a300cc | 4 weeks ago |
Ilya Bizyaev | bf84bf9e82 | 4 weeks ago |
SC | 363b29babb | 1 month ago |
min7-i | c1ff953f5c | 1 month ago |
Alex Baker | 63482e5db9 | 1 month ago |
Emin Tufan Çetin | 2f7dc0c7f1 | 1 month ago |
Lionel HANNEQUIN | d672507fae | 1 month ago |
Jonatan Nyberg | ce2a3c8a3f | 1 month ago |
sorifukobexomajepasiricupuva33 | 9cd114d68b | 2 months ago |
Patrick V. Leguizamon | 0e663f0e08 | 2 months ago |
Mayhm | 1d1efd008d | 2 months ago |
Alex Baker | 26ab3d5866 | 2 months ago |
Mayhm | 9a4fcbbd39 | 2 months ago |
Alex Baker | 72bfda9224 | 2 months ago |
Alex Baker | 1067de4183 | 2 months ago |
Alex Baker | d686b8c7e0 | 2 months ago |
Alex Baker | b2efb42d55 | 2 months ago |
Fabio Parri | 3448808c94 | 2 months ago |
Alex Baker | 06a9626052 | 2 months ago |
Alex Baker | e92ab7f7e1 | 2 months ago |
Alex Baker | 4ff7b18c0f | 2 months ago |
Alex Baker | 91887f6b17 | 2 months ago |
Alex Baker | cf30b56098 | 2 months ago |
Alex Baker | 9bcadaab5a | 2 months ago |
Alex Baker | be766074b0 | 2 months ago |
Ihor Hordiichuk | 64a42a3f61 | 2 months ago |
Mayhm | 7b65ba6f06 | 2 months ago |
109247019824 | ac2b270e9e | 2 months ago |
Alex Baker | db2ea0a039 | 2 months ago |
renovate[bot] | 08b78fe9f4 | 2 months ago |
Alex Baker | 1a1301ae3e | 2 months ago |
Milo Ivir | d00061aa7f | 2 months ago |
大王叫我来巡山 | 45add6ab32 | 2 months ago |
Pierfrancesco Passerini | af43737c4e | 2 months ago |
macpac59 | dd40e59b17 | 2 months ago |
gallegonovato | 13f3248a01 | 2 months ago |
renovate[bot] | f6972e3e30 | 2 months ago |
Alex Baker | 83cf48a836 | 2 months ago |
Alex Baker | b7b4747a04 | 2 months ago |
Alex Baker | 6bec2ceef0 | 2 months ago |
Milo Ivir | d1e60d6512 | 2 months ago |
bittin1ddc447d824349b2 | 2b85089d3a | 2 months ago |
ferranpujolcamins | 2a0ef9feb6 | 2 months ago |
109247019824 | 33adbbd884 | 2 months ago |
Alex Baker | c25eb2e0c5 | 2 months ago |
Alex Baker | 14026356eb | 2 months ago |
Alex Baker | b328651dd4 | 2 months ago |
Alex Baker | a0e9bfabeb | 2 months ago |
大王叫我来巡山 | a1ad421b33 | 2 months ago |
Mayhm | 3488a08af1 | 2 months ago |
gallegonovato | b71d1af516 | 2 months ago |
Alex Baker | 041dce8617 | 2 months ago |
Alex Baker | 3d92ca78dd | 2 months ago |
Alex Baker | a32fce2d8b | 2 months ago |
Alex Baker | 4fb3cda173 | 2 months ago |
Alex Baker | f33cc896dd | 2 months ago |
Alex Baker | 4d1d6a06a8 | 2 months ago |
Alex Baker | 2202516688 | 2 months ago |
Alex Baker | d4a5008ecb | 2 months ago |
Alex Baker | 08189e10f1 | 2 months ago |
Anonymous | d3e4c066d8 | 2 months ago |
Anonymous | bbc5ae4d6d | 2 months ago |
Anonymous | c6cc00cf07 | 2 months ago |
Anonymous | 22e8720021 | 2 months ago |
Anonymous | a3ce98f0ea | 2 months ago |
macpac59 | 258f607d52 | 2 months ago |
ngocanhtve | 927acae7e4 | 2 months ago |
Odweta | 49ad9bafe3 | 2 months ago |
Alex Baker | 6df616d9ce | 2 months ago |
Alex Baker | 157668e35a | 2 months ago |
Aslam Karachiwala | efdf343869 | 2 months ago |
renovate[bot] | 5606df17c5 | 2 months ago |
renovate[bot] | fc3b4971f4 | 2 months ago |
renovate[bot] | 6a1699bb33 | 2 months ago |
renovate[bot] | e49303d5ca | 2 months ago |
renovate[bot] | 4b55569b51 | 3 months ago |
renovate[bot] | 2d7145cde3 | 3 months ago |
renovate[bot] | f2ab8bed95 | 3 months ago |
renovate[bot] | a5bc4cf536 | 3 months ago |
renovate[bot] | 1b35372b3a | 3 months ago |
Alex Baker | c0fd4bf66a | 3 months ago |
renovate[bot] | 5d366f0d61 | 3 months ago |
renovate[bot] | d0635ac6f3 | 3 months ago |
renovate[bot] | 8d4cf4daa5 | 3 months ago |
renovate[bot] | d1e439e70e | 3 months ago |
renovate[bot] | 4d4c3e5193 | 3 months ago |
Alex Baker | 20f87061fd | 3 months ago |
renovate[bot] | c03e3747c6 | 3 months ago |
renovate[bot] | 925b1b9124 | 3 months ago |
Alex Baker | 43db712f64 | 3 months ago |
Alex Baker | 9d33a73ee6 | 3 months ago |
renovate[bot] | 391c600ce2 | 3 months ago |
renovate[bot] | ee4ae94817 | 3 months ago |
renovate[bot] | 70b4be1447 | 3 months ago |
Don Zouras | bc54d92789 | 3 months ago |
Сергій | 2f34724b95 | 3 months ago |
Alex Baker | 940fdc28dd | 3 months ago |
Alex Baker | 68542fce38 | 3 months ago |
renovate[bot] | 7ba2977100 | 4 months ago |
Don Zouras | cb242539f0 | 4 months ago |
bittin1ddc447d824349b2 | 304841f2c3 | 4 months ago |
Don Zouras | 819ea797e6 | 4 months ago |
abc0922001 | 2dbea57262 | 4 months ago |
Don Zouras | 516a916fd5 | 4 months ago |
109247019824 | 3bd52efc80 | 4 months ago |
renovate[bot] | 64af955ea7 | 4 months ago |
Milo Ivir | 4cc5ec9639 | 4 months ago |
大王叫我来巡山 | 0d9292e53a | 4 months ago |
Oğuz Ersen | 732ccf1913 | 4 months ago |
gallegonovato | a2852bdbbf | 4 months ago |
Don Zouras | 68790ad401 | 4 months ago |
Alex Baker | e9afacb595 | 4 months ago |
Alex Baker | cf182aceab | 4 months ago |
Alex Baker | db889d233a | 4 months ago |
Alex Baker | 457b89c092 | 4 months ago |
Don Zouras | ad53af1b6a | 4 months ago |
renovate[bot] | 2c32b08c97 | 4 months ago |
renovate[bot] | a2fcf57c9e | 4 months ago |
renovate[bot] | 59a61325f2 | 4 months ago |
vulewuxe86 | 38a6064677 | 4 months ago |
renovate[bot] | 67daccf3e8 | 4 months ago |
renovate[bot] | dfe829d2a1 | 4 months ago |
renovate[bot] | 23c64f4d28 | 4 months ago |
renovate[bot] | e4b8f694f3 | 4 months ago |
renovate[bot] | e667c80731 | 4 months ago |
renovate[bot] | 909b077e25 | 4 months ago |
Don Zouras | e6fab9ad45 | 4 months ago |
raulmagdalena | 9474f5b7af | 4 months ago |
Don Zouras | 1ee051d768 | 4 months ago |
Don Zouras | f42edaa158 | 4 months ago |
RayBB | b97eade59c | 4 months ago |
renovate[bot] | 41aa1ca65f | 4 months ago |
renovate[bot] | 3e9a13ea14 | 4 months ago |
renovate[bot] | d966e8a12b | 4 months ago |
renovate[bot] | 8ba4e64994 | 4 months ago |
109247019824 | ee792f1ceb | 4 months ago |
renovate[bot] | caa09163a1 | 4 months ago |
renovate[bot] | d270abf5b3 | 4 months ago |
renovate[bot] | 1ef530abad | 4 months ago |
renovate[bot] | df26a6dbb9 | 4 months ago |
renovate[bot] | 1882c3b7e0 | 5 months ago |
renovate[bot] | cb53a0ca9f | 5 months ago |
renovate[bot] | b2fdef1ae7 | 5 months ago |
renovate[bot] | defb16ce95 | 5 months ago |
renovate[bot] | 823f99b28a | 5 months ago |
renovate[bot] | 6df872b1a1 | 5 months ago |
renovate[bot] | 133b960583 | 5 months ago |
renovate[bot] | 2e6753faec | 5 months ago |
renovate[bot] | cb07c2c267 | 5 months ago |
renovate[bot] | 23757ab320 | 5 months ago |
Alex Baker | 1b6ce0e48e | 5 months ago |
Kakaeo | 5af012068f | 5 months ago |
Alex Baker | 6c9ffa57d7 | 6 months ago |
Alex Baker | 52c54b1eac | 6 months ago |
Alex Baker | c8d81b44b6 | 6 months ago |
renovate[bot] | ef27a50e42 | 6 months ago |
Alex Baker | bde1356e7f | 6 months ago |
Alex Baker | 6c031925ba | 6 months ago |
Alex Baker | 8058414137 | 6 months ago |
Alex Baker | 3e37ea50f0 | 6 months ago |
renovate[bot] | 62f5a9c492 | 6 months ago |
renovate[bot] | a84fd65722 | 6 months ago |
renovate[bot] | 517b2d8f1b | 6 months ago |
renovate[bot] | 90942bf0be | 6 months ago |
Alex Baker | 83c3d1c4ba | 6 months ago |
Software In Interlingua | 6362ece569 | 6 months ago |
renovate[bot] | 8df85041b8 | 6 months ago |
ngocanhtve | 6d85af4c34 | 6 months ago |
Olli | 63f001dd72 | 6 months ago |
renovate[bot] | de49a50944 | 6 months ago |
renovate[bot] | df20d2f593 | 6 months ago |
renovate[bot] | fd16772236 | 6 months ago |
renovate[bot] | b77caac255 | 6 months ago |
renovate[bot] | ad058ed09b | 6 months ago |
Alex Baker | 8312113d7b | 6 months ago |
Alex Baker | ee21cc660e | 6 months ago |
Alex Baker | 5edc481ffe | 6 months ago |
Alex Baker | d0360a4862 | 6 months ago |
Alex Baker | ac35002408 | 6 months ago |
Subham Jena | 582ebad0f0 | 6 months ago |
Shaban Mamedov | 684c47184a | 6 months ago |
ngocanhtve | ac7a519e4e | 6 months ago |
renovate[bot] | 5c2b41af9d | 6 months ago |
renovate[bot] | 13986cf380 | 6 months ago |
CennoxX | c4f0b404e9 | 6 months ago |
Alex Baker | 145b5afbc6 | 6 months ago |
elig0n | 0b87a206fe | 6 months ago |
mm4c | d0e70ceea8 | 6 months ago |
J. Lavoie | bf3546a878 | 6 months ago |
Alex Baker | 8895acbf6b | 6 months ago |
Alex Baker | a52b1200f5 | 6 months ago |
renovate[bot] | 23964e807a | 7 months ago |
Alex Baker | 287b106dd4 | 7 months ago |
renovate[bot] | 33bab626e0 | 7 months ago |
renovate[bot] | a980cd75cc | 7 months ago |
renovate[bot] | 7eac4ac223 | 7 months ago |
renovate[bot] | 82cb2f7d3f | 7 months ago |
renovate[bot] | da2646597c | 7 months ago |
renovate[bot] | 495855133c | 7 months ago |
renovate[bot] | 242cb61662 | 7 months ago |
renovate[bot] | ab8886f3dc | 7 months ago |
Alex Baker | e48e92d2e6 | 7 months ago |
Alex Baker | 5f22f5cd38 | 7 months ago |
Alex Baker | 8a47cc2934 | 7 months ago |
Alex Baker | 0d94729d37 | 7 months ago |
Alex Baker | 14599eb3c0 | 7 months ago |
Alex Baker | b477623524 | 7 months ago |
Alex Baker | c8bfb67b50 | 7 months ago |
Alex Baker | 0a36e58525 | 7 months ago |
Alex Baker | 94a719cb66 | 7 months ago |
Alex Baker | b5748aa8e6 | 7 months ago |
Alex Baker | 7fd5647cb8 | 7 months ago |
Alex Baker | 2545832d67 | 7 months ago |
Alex Baker | 738bf435db | 7 months ago |
renovate[bot] | ab02323f29 | 7 months ago |
Alex Baker | d73a9d2795 | 7 months ago |
Alex Baker | ebe67354b6 | 7 months ago |
Alex Baker | 58edc6b4d8 | 7 months ago |
Weblate (bot) | 78b2cdac06 | 7 months ago |
renovate[bot] | c3d7db0087 | 7 months ago |
renovate[bot] | d7b1770b85 | 7 months ago |
Weblate (bot) | bebb3165a5 | 7 months ago |
Alex Baker | ad1198aace | 7 months ago |
Alex Baker | 7ae77a81e1 | 7 months ago |
Weblate (bot) | 3e79dd5190 | 7 months ago |
renovate[bot] | 9d57a849bf | 7 months ago |
Alex Baker | 82103eb477 | 7 months ago |
renovate[bot] | 11fa9a2bbd | 7 months ago |
renovate[bot] | b65831120f | 7 months ago |
renovate[bot] | f26a90a4f9 | 7 months ago |
renovate[bot] | dd3aa20485 | 7 months ago |
renovate[bot] | 8c84e1af50 | 7 months ago |
renovate[bot] | dc1eac23b9 | 7 months ago |
renovate[bot] | 5883952883 | 7 months ago |
Alex Baker | 775289b058 | 7 months ago |
Alex Baker | ee500c24b1 | 7 months ago |
Igor Sorocean | 68fd36b14d | 7 months ago |
renovate[bot] | b8f265fa36 | 7 months ago |
Alex Baker | cf4e6c1273 | 7 months ago |
renovate[bot] | 0dcc577497 | 7 months ago |
kmj-99 | b525e8cab3 | 7 months ago |
renovate[bot] | db0ad280eb | 7 months ago |
Alex Baker | 5092f80dcc | 7 months ago |
Kazushi Hayama | 6bc42363dd | 7 months ago |
Michal Šmahel | 115461c7b0 | 7 months ago |
renovate[bot] | 369c508890 | 7 months ago |
bittin1ddc447d824349b2 | a432cc33cc | 7 months ago |
Alex Baker | e5b51150cb | 7 months ago |
renovate[bot] | d43639556e | 7 months ago |
Alex Baker | ef2dd8f202 | 7 months ago |
renovate[bot] | 6a73f6745c | 7 months ago |
renovate[bot] | 5185c14e44 | 7 months ago |
Olli | aa7ff0fa16 | 7 months ago |
renovate[bot] | 12b979d363 | 7 months ago |
Alex Baker | 082f741983 | 8 months ago |
Alex Baker | 0bdd83988f | 8 months ago |
Alex Baker | 60784c10b5 | 8 months ago |
Alex Baker | da8467ac56 | 8 months ago |
renovate[bot] | 434d067822 | 8 months ago |
renovate[bot] | 04af310285 | 8 months ago |
renovate[bot] | 5555771f45 | 8 months ago |
renovate[bot] | 35b60df0ff | 8 months ago |
renovate[bot] | fef19b4995 | 8 months ago |
Alex Baker | 4c25b81a4d | 8 months ago |
Alex Baker | 0f37f4859e | 8 months ago |
Alex Baker | ee3d3fa4f5 | 8 months ago |
Alex Baker | a32d35720a | 8 months ago |
Alex Baker | bf6fe02fe3 | 8 months ago |
Alex Baker | 6664defc16 | 8 months ago |
renovate[bot] | b318b930a5 | 8 months ago |
Loucura | 91d18fd675 | 8 months ago |
Alex Baker | 94b6d7569b | 8 months ago |
Alex Baker | e70f5f3b24 | 8 months ago |
renovate[bot] | 68c21c4b1f | 8 months ago |
renovate[bot] | cbcc7f9bee | 8 months ago |
Milo Ivir | ba394b9db4 | 8 months ago |
Eric | 13298aa3be | 8 months ago |
Alex Baker | 993c41b197 | 8 months ago |
Alex Baker | 2bfc46f32b | 8 months ago |
Alex Baker | 4c61353411 | 8 months ago |
Alex Baker | f8d3985e97 | 8 months ago |
Alex Baker | c2a9d21f01 | 8 months ago |
Alex Baker | 20c81417a0 | 8 months ago |
@ -1 +1 @@
|
||||
3.2.2
|
||||
3.3.1
|
||||
|
@ -1,50 +1,68 @@
|
||||
package com.todoroo.astrid.repeats
|
||||
|
||||
import com.natpryce.makeiteasy.MakeItEasy.with
|
||||
import org.tasks.data.entity.Task
|
||||
import com.todoroo.astrid.service.TaskCompleter
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import dagger.hilt.android.testing.UninstallModules
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.tasks.data.TaskDao
|
||||
import org.tasks.data.dao.TaskDao
|
||||
import org.tasks.injection.InjectingTestCase
|
||||
import org.tasks.injection.ProductionModule
|
||||
import org.tasks.makers.TaskMaker.COMPLETION_TIME
|
||||
import org.tasks.makers.TaskMaker.PARENT
|
||||
import org.tasks.makers.TaskMaker.RECUR
|
||||
import org.tasks.makers.TaskMaker.newTask
|
||||
import org.tasks.time.DateTime
|
||||
import org.tasks.time.DateTimeUtils2.currentTimeMillis
|
||||
import javax.inject.Inject
|
||||
|
||||
@UninstallModules(ProductionModule::class)
|
||||
@HiltAndroidTest
|
||||
class RepeatWithSubtasksTests : InjectingTestCase() {
|
||||
@Inject lateinit var taskDao: TaskDao
|
||||
@Inject lateinit var repeat: RepeatTaskHelper
|
||||
@Inject lateinit var taskCompleter: TaskCompleter
|
||||
|
||||
@Test
|
||||
fun uncompleteGrandchildren() = runBlocking {
|
||||
val grandparent = taskDao.createNew(newTask(with(RECUR, "RRULE:FREQ=DAILY")))
|
||||
val parent = taskDao.createNew(newTask(with(PARENT, grandparent)))
|
||||
val child = taskDao.createNew(newTask(
|
||||
with(PARENT, parent),
|
||||
with(COMPLETION_TIME, DateTime())
|
||||
))
|
||||
val grandparent = taskDao.createNew(
|
||||
Task(
|
||||
recurrence = "RRULE:FREQ=DAILY"
|
||||
)
|
||||
)
|
||||
val parent = taskDao.createNew(
|
||||
Task(
|
||||
parent = grandparent
|
||||
)
|
||||
)
|
||||
val child = taskDao.createNew(
|
||||
Task(
|
||||
parent = parent,
|
||||
completionDate = currentTimeMillis(),
|
||||
)
|
||||
)
|
||||
|
||||
repeat.handleRepeat(taskDao.fetch(grandparent)!!)
|
||||
assertTrue(taskDao.fetch(child)!!.isCompleted)
|
||||
|
||||
taskCompleter.setComplete(grandparent)
|
||||
|
||||
assertFalse(taskDao.fetch(child)!!.isCompleted)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun uncompleteGoogleTaskChildren() = runBlocking {
|
||||
val parent = taskDao.createNew(newTask(with(RECUR, "RRULE:FREQ=DAILY")))
|
||||
val child = taskDao.createNew(newTask(
|
||||
with(PARENT, parent),
|
||||
with(COMPLETION_TIME, DateTime())
|
||||
))
|
||||
val parent = taskDao.createNew(
|
||||
Task(
|
||||
recurrence = "RRULE:FREQ=DAILY"
|
||||
)
|
||||
)
|
||||
val child = taskDao.createNew(
|
||||
Task(
|
||||
parent = parent,
|
||||
completionDate = currentTimeMillis(),
|
||||
)
|
||||
)
|
||||
|
||||
assertTrue(taskDao.fetch(child)!!.isCompleted)
|
||||
|
||||
repeat.handleRepeat(taskDao.fetch(parent)!!)
|
||||
taskCompleter.setComplete(parent)
|
||||
|
||||
assertFalse(taskDao.fetch(child)!!.isCompleted)
|
||||
}
|
||||
|
@ -0,0 +1,161 @@
|
||||
package org.tasks.ui.editviewmodel
|
||||
|
||||
import com.todoroo.astrid.core.BuiltInFilterExposer
|
||||
import org.tasks.data.entity.Task
|
||||
import com.todoroo.astrid.service.TaskDeleter
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import dagger.hilt.android.testing.UninstallModules
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.tasks.LocalBroadcastManager
|
||||
import org.tasks.analytics.Firebase
|
||||
import org.tasks.billing.Inventory
|
||||
import org.tasks.data.dao.DeletionDao
|
||||
import org.tasks.data.dao.TaskDao
|
||||
import org.tasks.injection.InjectingTestCase
|
||||
import org.tasks.injection.ProductionModule
|
||||
import org.tasks.preferences.Preferences
|
||||
import org.tasks.time.DateTimeUtils2.currentTimeMillis
|
||||
import org.tasks.ui.TaskListViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@UninstallModules(ProductionModule::class)
|
||||
@HiltAndroidTest
|
||||
class TaskListViewModelTest : InjectingTestCase() {
|
||||
private lateinit var viewModel: TaskListViewModel
|
||||
@Inject lateinit var preferences: Preferences
|
||||
@Inject lateinit var taskDao: TaskDao
|
||||
@Inject lateinit var taskDeleter: TaskDeleter
|
||||
@Inject lateinit var deletionDao: DeletionDao
|
||||
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
|
||||
@Inject lateinit var inventory: Inventory
|
||||
@Inject lateinit var firebase: Firebase
|
||||
|
||||
@Before
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
viewModel = TaskListViewModel(
|
||||
context = context,
|
||||
preferences = preferences,
|
||||
taskDao = taskDao,
|
||||
deletionDao = deletionDao,
|
||||
taskDeleter = taskDeleter,
|
||||
localBroadcastManager = localBroadcastManager,
|
||||
inventory = inventory,
|
||||
firebase = firebase,
|
||||
)
|
||||
viewModel.setFilter(BuiltInFilterExposer.getMyTasksFilter(context.resources))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun clearCompletedTask() = runBlocking {
|
||||
val task = taskDao.createNew(
|
||||
Task(completionDate = currentTimeMillis())
|
||||
)
|
||||
|
||||
clearCompleted()
|
||||
|
||||
assertTrue(taskDao.fetch(task)!!.isDeleted)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dontDeleteTaskWithRecurringParent() = runBlocking {
|
||||
val parent = taskDao.createNew(
|
||||
Task(
|
||||
recurrence = "RRULE:FREQ=DAILY;INTERVAL=1"
|
||||
)
|
||||
)
|
||||
val child = taskDao.createNew(
|
||||
Task(
|
||||
parent = parent,
|
||||
completionDate = currentTimeMillis(),
|
||||
)
|
||||
)
|
||||
|
||||
clearCompleted()
|
||||
|
||||
assertFalse(taskDao.fetch(child)!!.isDeleted)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dontDeleteTaskWithRecurringGrandparent() = runBlocking {
|
||||
val grandparent = taskDao.createNew(
|
||||
Task(recurrence = "RRULE:FREQ=DAILY;INTERVAL=1")
|
||||
)
|
||||
val parent = taskDao.createNew(
|
||||
Task(parent = grandparent)
|
||||
)
|
||||
val child = taskDao.createNew(
|
||||
Task(
|
||||
parent = parent,
|
||||
completionDate = currentTimeMillis(),
|
||||
)
|
||||
)
|
||||
|
||||
clearCompleted()
|
||||
|
||||
assertFalse(taskDao.fetch(child)!!.isDeleted)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun clearGrandchildWithNoRecurringAncestors() = runBlocking {
|
||||
val grandparent = taskDao.createNew(Task())
|
||||
val parent = taskDao.createNew(
|
||||
Task(parent = grandparent)
|
||||
)
|
||||
val child = taskDao.createNew(
|
||||
Task(
|
||||
parent = parent,
|
||||
completionDate = currentTimeMillis(),
|
||||
)
|
||||
)
|
||||
|
||||
clearCompleted()
|
||||
|
||||
assertTrue(taskDao.fetch(child)!!.isDeleted)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun clearGrandchildWithCompletedRecurringAncestor() = runBlocking {
|
||||
val grandparent = taskDao.createNew(
|
||||
Task(
|
||||
recurrence = "RRULE:FREQ=DAILY;INTERVAL=1",
|
||||
completionDate = currentTimeMillis(),
|
||||
)
|
||||
)
|
||||
val parent = taskDao.createNew(
|
||||
Task(parent = grandparent)
|
||||
)
|
||||
val child = taskDao.createNew(
|
||||
Task(
|
||||
parent = parent,
|
||||
completionDate = currentTimeMillis(),
|
||||
)
|
||||
)
|
||||
|
||||
clearCompleted()
|
||||
|
||||
assertTrue(taskDao.fetch(child)!!.isDeleted)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun clearHiddenSubtask() = runBlocking {
|
||||
preferences.showCompleted = false
|
||||
val parent = taskDao.createNew(Task())
|
||||
val child = taskDao.createNew(
|
||||
Task(
|
||||
parent = parent,
|
||||
completionDate = currentTimeMillis(),
|
||||
)
|
||||
)
|
||||
|
||||
clearCompleted()
|
||||
|
||||
assertTrue(taskDao.fetch(child)!!.isDeleted)
|
||||
}
|
||||
|
||||
private suspend fun clearCompleted() = viewModel.markDeleted(viewModel.getTasksToClear())
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package com.todoroo.andlib.data
|
||||
|
||||
import com.todoroo.andlib.sql.Field
|
||||
|
||||
class Property internal constructor(val name: String?, expression: String) : Field(expression) {
|
||||
|
||||
constructor(table: Table, columnName: String) : this(columnName, "${table.name()}.$columnName")
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
package com.todoroo.astrid.activity
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.todoroo.astrid.activity.MainActivity.Companion.LOAD_FILTER
|
||||
import com.todoroo.astrid.activity.MainActivity.Companion.OPEN_FILTER
|
||||
import com.todoroo.astrid.api.CaldavFilter
|
||||
import com.todoroo.astrid.api.CustomFilter
|
||||
import com.todoroo.astrid.api.Filter
|
||||
import com.todoroo.astrid.api.GtasksFilter
|
||||
import com.todoroo.astrid.api.TagFilter
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.tasks.LocalBroadcastManager
|
||||
import org.tasks.R
|
||||
import org.tasks.Tasks.Companion.IS_GENERIC
|
||||
import org.tasks.billing.Inventory
|
||||
import org.tasks.compose.drawer.DrawerItem
|
||||
import org.tasks.data.dao.CaldavDao
|
||||
import org.tasks.data.NO_COUNT
|
||||
import org.tasks.data.entity.Task
|
||||
import org.tasks.data.dao.TaskDao
|
||||
import org.tasks.data.count
|
||||
import org.tasks.filters.FilterProvider
|
||||
import org.tasks.filters.NavigationDrawerSubheader
|
||||
import org.tasks.filters.PlaceFilter
|
||||
import org.tasks.preferences.DefaultFilterProvider
|
||||
import org.tasks.preferences.Preferences
|
||||
import org.tasks.themes.ColorProvider
|
||||
import org.tasks.themes.CustomIcons
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class MainActivityViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val defaultFilterProvider: DefaultFilterProvider,
|
||||
private val filterProvider: FilterProvider,
|
||||
private val taskDao: TaskDao,
|
||||
private val localBroadcastManager: LocalBroadcastManager,
|
||||
private val inventory: Inventory,
|
||||
private val colorProvider: ColorProvider,
|
||||
private val caldavDao: CaldavDao,
|
||||
private val preferences: Preferences,
|
||||
) : ViewModel() {
|
||||
|
||||
data class State(
|
||||
val begForMoney: Boolean = false,
|
||||
val filter: Filter,
|
||||
val task: Task? = null,
|
||||
val drawerOpen: Boolean = false,
|
||||
val drawerItems: ImmutableList<DrawerItem> = persistentListOf(),
|
||||
)
|
||||
|
||||
private val _state = MutableStateFlow(
|
||||
State(
|
||||
filter = savedStateHandle.get<Filter>(OPEN_FILTER)
|
||||
?: savedStateHandle.get<String>(LOAD_FILTER)?.let {
|
||||
runBlocking { defaultFilterProvider.getFilterFromPreference(it) }
|
||||
}
|
||||
?: runBlocking { defaultFilterProvider.getStartupFilter() },
|
||||
begForMoney = if (IS_GENERIC) !inventory.hasTasksAccount else !inventory.hasPro,
|
||||
)
|
||||
)
|
||||
val state = _state.asStateFlow()
|
||||
|
||||
private val refreshReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
when (intent?.action) {
|
||||
LocalBroadcastManager.REFRESH,
|
||||
LocalBroadcastManager.REFRESH_LIST -> updateFilters()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun resetFilter() {
|
||||
setFilter(defaultFilterProvider.getDefaultOpenFilter())
|
||||
}
|
||||
|
||||
fun setFilter(
|
||||
filter: Filter,
|
||||
task: Task? = null,
|
||||
) {
|
||||
if (filter == _state.value.filter && task == null) {
|
||||
return
|
||||
}
|
||||
_state.update {
|
||||
it.copy(
|
||||
filter = filter,
|
||||
task = task,
|
||||
)
|
||||
}
|
||||
updateFilters()
|
||||
defaultFilterProvider.setLastViewedFilter(filter)
|
||||
}
|
||||
|
||||
fun setDrawerOpen(open: Boolean) {
|
||||
_state.update { it.copy(drawerOpen = open) }
|
||||
}
|
||||
|
||||
init {
|
||||
localBroadcastManager.registerRefreshListReceiver(refreshReceiver)
|
||||
updateFilters()
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
localBroadcastManager.unregisterReceiver(refreshReceiver)
|
||||
}
|
||||
|
||||
fun updateFilters() = viewModelScope.launch(Dispatchers.Default) {
|
||||
val selected = state.value.filter
|
||||
filterProvider
|
||||
.drawerItems()
|
||||
.map { item ->
|
||||
when (item) {
|
||||
is Filter ->
|
||||
DrawerItem.Filter(
|
||||
title = item.title ?: "",
|
||||
icon = getIcon(item),
|
||||
color = getColor(item),
|
||||
count = item.count.takeIf { it != NO_COUNT } ?: try {
|
||||
taskDao.count(item)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
0
|
||||
},
|
||||
selected = item.areItemsTheSame(selected),
|
||||
shareCount = if (item is CaldavFilter) item.principals else 0,
|
||||
type = { item },
|
||||
)
|
||||
is NavigationDrawerSubheader ->
|
||||
DrawerItem.Header(
|
||||
title = item.title ?: "",
|
||||
collapsed = item.isCollapsed,
|
||||
hasError = item.error,
|
||||
canAdd = item.addIntent != null,
|
||||
type = { item },
|
||||
)
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
}
|
||||
.let { filters -> _state.update { it.copy(drawerItems = filters.toPersistentList()) } }
|
||||
}
|
||||
|
||||
private fun getColor(filter: Filter): Int {
|
||||
if (filter.tint != 0) {
|
||||
val color = colorProvider.getThemeColor(filter.tint, true)
|
||||
if (color.isFree || inventory.purchasedThemes()) {
|
||||
return color.primaryColor
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private fun getIcon(filter: Filter): Int {
|
||||
if (filter.icon < 1000 || filter.icon == CustomIcons.PLACE || inventory.hasPro) {
|
||||
val icon = CustomIcons.getIconResId(filter.icon)
|
||||
if (icon != null) {
|
||||
return icon
|
||||
}
|
||||
}
|
||||
return when (filter) {
|
||||
is TagFilter -> R.drawable.ic_outline_label_24px
|
||||
is GtasksFilter,
|
||||
is CaldavFilter -> R.drawable.ic_list_24px
|
||||
|
||||
is CustomFilter -> R.drawable.ic_outline_filter_list_24px
|
||||
is PlaceFilter -> R.drawable.ic_outline_place_24px
|
||||
else -> filter.icon
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleCollapsed(subheader: NavigationDrawerSubheader) = viewModelScope.launch {
|
||||
val collapsed = !subheader.isCollapsed
|
||||
when (subheader.subheaderType) {
|
||||
NavigationDrawerSubheader.SubheaderType.PREFERENCE -> {
|
||||
preferences.setBoolean(subheader.id.toInt(), collapsed)
|
||||
localBroadcastManager.broadcastRefreshList()
|
||||
}
|
||||
NavigationDrawerSubheader.SubheaderType.GOOGLE_TASKS,
|
||||
NavigationDrawerSubheader.SubheaderType.CALDAV,
|
||||
NavigationDrawerSubheader.SubheaderType.TASKS,
|
||||
NavigationDrawerSubheader.SubheaderType.ETESYNC -> {
|
||||
caldavDao.setCollapsed(subheader.id, collapsed)
|
||||
localBroadcastManager.broadcastRefreshList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setTask(task: Task?) {
|
||||
_state.update { it.copy(task = task) }
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
package com.todoroo.astrid.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.todoroo.astrid.api.FilterListItem
|
||||
import org.tasks.databinding.FilterAdapterActionBinding
|
||||
import org.tasks.themes.DrawableUtil
|
||||
|
||||
class ActionViewHolder internal constructor(
|
||||
private val context: Context,
|
||||
itemView: View,
|
||||
private val onClick: ((FilterListItem?) -> Unit)?) : RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
private val row: View
|
||||
private val text: TextView
|
||||
private val icon: ImageView
|
||||
|
||||
init {
|
||||
FilterAdapterActionBinding.bind(itemView).let {
|
||||
row = it.row
|
||||
text = it.text
|
||||
icon = it.icon
|
||||
}
|
||||
}
|
||||
|
||||
fun bind(filter: FilterListItem) {
|
||||
text.text = filter.listingTitle
|
||||
icon.setImageDrawable(DrawableUtil.getWrapped(context, filter.icon))
|
||||
if (onClick != null) {
|
||||
row.setOnClickListener {
|
||||
onClick.invoke(filter)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package com.todoroo.astrid.adapter
|
||||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
class SeparatorViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView)
|
@ -1,122 +0,0 @@
|
||||
package com.todoroo.astrid.api;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.todoroo.andlib.sql.Criterion;
|
||||
import com.todoroo.andlib.sql.Join;
|
||||
import com.todoroo.andlib.sql.QueryTemplate;
|
||||
import com.todoroo.astrid.data.Task;
|
||||
|
||||
import org.tasks.R;
|
||||
import org.tasks.data.CaldavCalendar;
|
||||
import org.tasks.data.CaldavTask;
|
||||
import org.tasks.data.TaskDao;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class CaldavFilter extends Filter {
|
||||
|
||||
/** Parcelable Creator Object */
|
||||
public static final Parcelable.Creator<CaldavFilter> CREATOR =
|
||||
new Parcelable.Creator<>() {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public CaldavFilter createFromParcel(Parcel source) {
|
||||
CaldavFilter item = new CaldavFilter();
|
||||
item.readFromParcel(source);
|
||||
return item;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public CaldavFilter[] newArray(int size) {
|
||||
return new CaldavFilter[size];
|
||||
}
|
||||
};
|
||||
|
||||
private CaldavCalendar calendar;
|
||||
|
||||
private CaldavFilter() {
|
||||
super();
|
||||
}
|
||||
|
||||
public CaldavFilter(CaldavCalendar calendar) {
|
||||
super(calendar.getName(), queryTemplate(calendar), getValuesForNewTask(calendar));
|
||||
this.calendar = calendar;
|
||||
id = calendar.getId();
|
||||
tint = calendar.getColor();
|
||||
icon = calendar.getIcon();
|
||||
order = calendar.getOrder();
|
||||
}
|
||||
|
||||
private static QueryTemplate queryTemplate(CaldavCalendar caldavCalendar) {
|
||||
return new QueryTemplate()
|
||||
.join(Join.left(CaldavTask.TABLE, Task.ID.eq(CaldavTask.TASK)))
|
||||
.where(getCriterion(caldavCalendar));
|
||||
}
|
||||
|
||||
private static Criterion getCriterion(CaldavCalendar caldavCalendar) {
|
||||
return Criterion.and(
|
||||
TaskDao.TaskCriteria.activeAndVisible(),
|
||||
CaldavTask.DELETED.eq(0),
|
||||
CaldavTask.CALENDAR.eq(caldavCalendar.getUuid()));
|
||||
}
|
||||
|
||||
private static Map<String, Object> getValuesForNewTask(CaldavCalendar caldavCalendar) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put(CaldavTask.KEY, caldavCalendar.getUuid());
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getUuid() {
|
||||
return calendar.getUuid();
|
||||
}
|
||||
|
||||
public String getAccount() {
|
||||
return calendar.getAccount();
|
||||
}
|
||||
|
||||
public CaldavCalendar getCalendar() {
|
||||
return calendar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return calendar.getAccess() == CaldavCalendar.ACCESS_READ_ONLY;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeParcelable(calendar, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readFromParcel(Parcel source) {
|
||||
super.readFromParcel(source);
|
||||
calendar = source.readParcelable(getClass().getClassLoader());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsManualSort() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMenu() {
|
||||
return R.menu.menu_caldav_list_fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull FilterListItem other) {
|
||||
return super.areContentsTheSame(other)
|
||||
&& Objects.equals(calendar, ((CaldavFilter) other).calendar);
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.todoroo.astrid.api
|
||||
|
||||
import org.tasks.data.sql.Criterion.Companion.and
|
||||
import org.tasks.data.sql.Join.Companion.left
|
||||
import org.tasks.data.sql.QueryTemplate
|
||||
import com.todoroo.andlib.utility.AndroidUtilities
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.tasks.data.entity.CaldavCalendar
|
||||
import org.tasks.data.entity.CaldavTask
|
||||
import org.tasks.data.NO_COUNT
|
||||
import org.tasks.data.entity.Task
|
||||
import org.tasks.data.dao.TaskDao.TaskCriteria.activeAndVisible
|
||||
|
||||
@Parcelize
|
||||
data class CaldavFilter(
|
||||
val calendar: CaldavCalendar,
|
||||
val principals: Int = 0,
|
||||
override val count: Int = NO_COUNT,
|
||||
) : Filter {
|
||||
override val title: String?
|
||||
get() = calendar.name
|
||||
override val sql: String
|
||||
get() = QueryTemplate()
|
||||
.join(left(CaldavTask.TABLE, Task.ID.eq(CaldavTask.TASK)))
|
||||
.where(
|
||||
and(
|
||||
activeAndVisible(),
|
||||
CaldavTask.DELETED.eq(0),
|
||||
CaldavTask.CALENDAR.eq(calendar.uuid)
|
||||
)
|
||||
)
|
||||
.toString()
|
||||
override val valuesForNewTasks: String
|
||||
get() = AndroidUtilities.mapToSerializedString(mapOf(CaldavTask.KEY to calendar.uuid!!))
|
||||
|
||||
override val order: Int
|
||||
get() = calendar.order
|
||||
|
||||
override val tint: Int
|
||||
get() = calendar.color
|
||||
override val icon: Int
|
||||
get() = calendar.getIcon()!!
|
||||
|
||||
val uuid: String
|
||||
get() = calendar.uuid!!
|
||||
val account: String
|
||||
get() = calendar.account!!
|
||||
|
||||
override val isReadOnly: Boolean
|
||||
get() = calendar.access == CaldavCalendar.ACCESS_READ_ONLY
|
||||
|
||||
override fun supportsManualSort() = true
|
||||
|
||||
override fun areItemsTheSame(other: FilterListItem): Boolean {
|
||||
return other is CaldavFilter && calendar.id == other.calendar.id
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
package com.todoroo.astrid.api;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.tasks.R;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class CustomFilter extends Filter {
|
||||
|
||||
/** Parcelable Creator Object */
|
||||
public static final Parcelable.Creator<CustomFilter> CREATOR =
|
||||
new Parcelable.Creator<>() {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public CustomFilter createFromParcel(Parcel source) {
|
||||
return new CustomFilter(source);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public CustomFilter[] newArray(int size) {
|
||||
return new CustomFilter[size];
|
||||
}
|
||||
};
|
||||
|
||||
private String criterion;
|
||||
|
||||
public CustomFilter(@NonNull org.tasks.data.Filter filter) {
|
||||
super(filter.getTitle(), filter.getSql(), filter.getValuesAsMap());
|
||||
id = filter.getId();
|
||||
criterion = filter.getCriterion();
|
||||
tint = filter.getColor();
|
||||
icon = filter.getIcon();
|
||||
order = filter.getOrder();
|
||||
}
|
||||
|
||||
private CustomFilter(Parcel parcel) {
|
||||
readFromParcel(parcel);
|
||||
}
|
||||
|
||||
public String getCriterion() {
|
||||
return criterion;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeString(criterion);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readFromParcel(Parcel source) {
|
||||
super.readFromParcel(source);
|
||||
criterion = source.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMenu() {
|
||||
return getId() > 0 ? R.menu.menu_custom_filter : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull FilterListItem other) {
|
||||
return super.areContentsTheSame(other)
|
||||
&& Objects.equals(criterion, ((CustomFilter) other).criterion);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.todoroo.astrid.api
|
||||
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.tasks.themes.CustomIcons
|
||||
|
||||
@Parcelize
|
||||
data class CustomFilter(
|
||||
val filter: org.tasks.data.entity.Filter,
|
||||
) : Filter {
|
||||
override val title: String?
|
||||
get() = filter.title
|
||||
override val sql: String
|
||||
get() = filter.sql!!
|
||||
|
||||
override val valuesForNewTasks: String?
|
||||
get() = filter.values
|
||||
|
||||
val criterion: String?
|
||||
get() = filter.criterion
|
||||
|
||||
override val order: Int
|
||||
get() = filter.order
|
||||
|
||||
val id: Long
|
||||
get() = filter.id
|
||||
override val icon: Int
|
||||
get() = filter.icon ?: CustomIcons.FILTER
|
||||
override val tint: Int
|
||||
get() = filter.color ?: 0
|
||||
|
||||
override fun areItemsTheSame(other: FilterListItem): Boolean {
|
||||
return other is CustomFilter && id == other.id
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.todoroo.astrid.api
|
||||
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
class EmptyFilter(override val sql: String? = "WHERE 0", override val title: String? = null) : Filter {
|
||||
override fun areItemsTheSame(other: FilterListItem): Boolean = false
|
||||
}
|
@ -1,247 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.astrid.api;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import androidx.annotation.MenuRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.todoroo.andlib.sql.QueryTemplate;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A <code>FilterListFilter</code> allows users to display tasks that have something in common.
|
||||
*
|
||||
* <p>A plug-in can expose new <code>FilterListFilter</code>s to the system by responding to the
|
||||
* <code>com.todoroo.astrid.GET_FILTERS</code> broadcast intent.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*/
|
||||
public class Filter extends FilterListItem {
|
||||
|
||||
/** Parcelable Creator Object */
|
||||
public static final Parcelable.Creator<Filter> CREATOR =
|
||||
new Parcelable.Creator<>() {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public Filter createFromParcel(Parcel source) {
|
||||
Filter item = new Filter();
|
||||
item.readFromParcel(source);
|
||||
return item;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public Filter[] newArray(int size) {
|
||||
return new Filter[size];
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Values to apply to a task when quick-adding a task from this filter. For example, when a user
|
||||
* views tasks tagged 'ABC', the tasks they create should also be tagged 'ABC'. If set to null, no
|
||||
* additional values will be stored for a task. Can use {@link PermaSql}
|
||||
*/
|
||||
public final Map<String, Object> valuesForNewTasks = new HashMap<>();
|
||||
/**
|
||||
* {@link PermaSql} query for this filter. The query will be appended to the select statement
|
||||
* after "<code>SELECT fields FROM table %s</code>". It is recommended that you use a {@link
|
||||
* QueryTemplate} to construct your query.
|
||||
*
|
||||
* <p>Examples:
|
||||
*
|
||||
* <ul>
|
||||
* <li><code>"WHERE completionDate = 0"</code>
|
||||
* <li><code>"INNER JOIN " +
|
||||
* Constants.TABLE_METADATA + " ON metadata.task = tasks.id WHERE
|
||||
* metadata.namespace = " + NAMESPACE + " AND metadata.key = 'a' AND
|
||||
* metadata.value = 'b' GROUP BY tasks.id ORDER BY tasks.title"</code>
|
||||
* </ul>
|
||||
*/
|
||||
public String sqlQuery;
|
||||
/**
|
||||
* Field for holding a modified sqlQuery based on sqlQuery. Useful for adjusting query for
|
||||
* sort/subtasks without breaking the equality checking based on sqlQuery.
|
||||
*/
|
||||
private String filterOverride;
|
||||
|
||||
public Filter(String listingTitle, QueryTemplate sqlQuery) {
|
||||
this(listingTitle, sqlQuery, Collections.emptyMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility constructor for creating a Filter object
|
||||
*
|
||||
* @param listingTitle Title of this item as displayed on the lists page, e.g. Inbox
|
||||
* @param sqlQuery SQL query for this list (see {@link #sqlQuery} for examples).
|
||||
*/
|
||||
protected Filter(
|
||||
String listingTitle, QueryTemplate sqlQuery, Map<String, Object> valuesForNewTasks) {
|
||||
this(listingTitle, sqlQuery == null ? null : sqlQuery.toString(), valuesForNewTasks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility constructor for creating a Filter object
|
||||
*
|
||||
* @param listingTitle Title of this item as displayed on the lists page, e.g. Inbox
|
||||
* @param sqlQuery SQL query for this list (see {@link #sqlQuery} for examples).
|
||||
*/
|
||||
Filter(String listingTitle, String sqlQuery, Map<String, Object> valuesForNewTasks) {
|
||||
this.listingTitle = listingTitle;
|
||||
this.sqlQuery = sqlQuery;
|
||||
this.filterOverride = null;
|
||||
if (valuesForNewTasks != null) {
|
||||
this.valuesForNewTasks.putAll(valuesForNewTasks);
|
||||
}
|
||||
}
|
||||
|
||||
protected Filter() {}
|
||||
|
||||
public String getOriginalSqlQuery() {
|
||||
return sqlQuery;
|
||||
}
|
||||
|
||||
public String getSqlQuery() {
|
||||
if (filterOverride != null) {
|
||||
return filterOverride;
|
||||
}
|
||||
return sqlQuery;
|
||||
}
|
||||
|
||||
// --- parcelable
|
||||
|
||||
public void setFilterQueryOverride(String filterOverride) {
|
||||
this.filterOverride = filterOverride;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((sqlQuery == null) ? 0 : sqlQuery.hashCode());
|
||||
result = prime * result + ((listingTitle == null) ? 0 : listingTitle.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Filter other = (Filter) obj;
|
||||
if (sqlQuery == null) {
|
||||
if (other.sqlQuery != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!sqlQuery.equals(other.sqlQuery)) {
|
||||
return false;
|
||||
}
|
||||
if (listingTitle == null) {
|
||||
return other.listingTitle == null;
|
||||
} else return listingTitle.equals(other.listingTitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getItemType() {
|
||||
return Type.ITEM;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeString(""); // old title
|
||||
dest.writeString(sqlQuery);
|
||||
dest.writeMap(valuesForNewTasks);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readFromParcel(Parcel source) {
|
||||
super.readFromParcel(source);
|
||||
source.readString(); // old title
|
||||
sqlQuery = source.readString();
|
||||
source.readMap(valuesForNewTasks, getClass().getClassLoader());
|
||||
}
|
||||
|
||||
public boolean supportsAstridSorting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean supportsManualSort() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean supportsHiddenTasks() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean supportsSubtasks() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean supportsSorting() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isWritable() {
|
||||
return !isReadOnly();
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasBeginningMenu() {
|
||||
return getBeginningMenu() != 0;
|
||||
}
|
||||
|
||||
public @MenuRes int getBeginningMenu() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean hasMenu() {
|
||||
return getMenu() != 0;
|
||||
}
|
||||
|
||||
public @MenuRes int getMenu() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Filter{"
|
||||
+ "sqlQuery='"
|
||||
+ sqlQuery
|
||||
+ '\''
|
||||
+ ", filterOverride='"
|
||||
+ filterOverride
|
||||
+ '\''
|
||||
+ ", valuesForNewTasks="
|
||||
+ valuesForNewTasks
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull FilterListItem other) {
|
||||
return other instanceof Filter && Objects.equals(sqlQuery, ((Filter) other).sqlQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull FilterListItem other) {
|
||||
return super.areContentsTheSame(other)
|
||||
&& Objects.equals(sqlQuery, ((Filter) other).sqlQuery);
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package com.todoroo.astrid.api
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.tasks.data.NO_COUNT
|
||||
import org.tasks.data.NO_ORDER
|
||||
|
||||
interface Filter : FilterListItem, Parcelable {
|
||||
val valuesForNewTasks: String?
|
||||
get() = null
|
||||
val sql: String?
|
||||
val icon: Int
|
||||
get() = -1
|
||||
val title: String?
|
||||
val tint: Int
|
||||
get() = 0
|
||||
@Deprecated("Remove this")
|
||||
val count: Int
|
||||
get() = NO_COUNT
|
||||
val order: Int
|
||||
get() = NO_ORDER
|
||||
override val itemType: FilterListItem.Type
|
||||
get() = FilterListItem.Type.ITEM
|
||||
val isReadOnly: Boolean
|
||||
get() = false
|
||||
val isWritable: Boolean
|
||||
get() = !isReadOnly
|
||||
|
||||
fun supportsManualSort(): Boolean = false
|
||||
fun supportsHiddenTasks(): Boolean = true
|
||||
fun supportsSubtasks(): Boolean = true
|
||||
fun supportsSorting(): Boolean = true
|
||||
}
|
||||
|
||||
@Deprecated("Use manual ordering")
|
||||
interface AstridOrderingFilter : Filter {
|
||||
var filterOverride: String?
|
||||
|
||||
fun getSqlQuery(): String = filterOverride ?: sql!!
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
data class FilterImpl(
|
||||
override val title: String? = null,
|
||||
override val sql: String? = null,
|
||||
override val valuesForNewTasks: String? = null,
|
||||
override val icon: Int = -1,
|
||||
override val tint: Int = 0,
|
||||
) : Filter {
|
||||
override fun areItemsTheSame(other: FilterListItem): Boolean {
|
||||
return other is Filter && sql == other.sql
|
||||
}
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
|
||||
package com.todoroo.astrid.api;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.tasks.R;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents an item displayed by Astrid's FilterListActivity
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*/
|
||||
public abstract class FilterListItem implements Parcelable {
|
||||
|
||||
public static final int NO_ORDER = -1;
|
||||
|
||||
/** Title of this item displayed on the Filters page */
|
||||
public String listingTitle = null;
|
||||
|
||||
public long id = 0;
|
||||
public int icon = -1;
|
||||
public int tint = 0;
|
||||
public int count = -1;
|
||||
public int principals = 0;
|
||||
public int order = NO_ORDER;
|
||||
|
||||
public abstract Type getItemType();
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(listingTitle);
|
||||
dest.writeInt(icon);
|
||||
dest.writeInt(tint);
|
||||
dest.writeInt(count);
|
||||
dest.writeInt(order);
|
||||
dest.writeLong(id);
|
||||
}
|
||||
|
||||
// --- parcelable helpers
|
||||
|
||||
/** Utility method to read FilterListItem properties from a parcel. */
|
||||
protected void readFromParcel(Parcel source) {
|
||||
listingTitle = source.readString();
|
||||
icon = source.readInt();
|
||||
tint = source.readInt();
|
||||
count = source.readInt();
|
||||
order = source.readInt();
|
||||
id = source.readLong();
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean areItemsTheSame(@NonNull FilterListItem other) {
|
||||
return getClass().equals(other.getClass()) && id == other.id;
|
||||
}
|
||||
|
||||
public boolean areContentsTheSame(@NonNull FilterListItem other) {
|
||||
return Objects.equals(listingTitle, other.listingTitle)
|
||||
&& icon == other.icon
|
||||
&& tint == other.tint
|
||||
&& count == other.count
|
||||
&& order == other.order
|
||||
&& principals == other.principals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FilterListItem{" +
|
||||
"listingTitle='" + listingTitle + '\'' +
|
||||
", id=" + id +
|
||||
", icon=" + icon +
|
||||
", tint=" + tint +
|
||||
", count=" + count +
|
||||
", principals=" + principals +
|
||||
", order=" + order +
|
||||
'}';
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
ITEM(R.layout.filter_adapter_row),
|
||||
ACTION(R.layout.filter_adapter_action),
|
||||
SUBHEADER(R.layout.filter_adapter_subheader),
|
||||
SEPARATOR(R.layout.filter_adapter_separator);
|
||||
|
||||
public final int layout;
|
||||
|
||||
Type(@LayoutRes int layout) {
|
||||
this.layout = layout;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue