Skip to content

Commit edff059

Browse files
committed
Create pre-filled Demo content
1 parent 528850a commit edff059

File tree

7 files changed

+344
-1
lines changed

7 files changed

+344
-1
lines changed

tasks-app-android/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,10 @@ dependencies {
170170
implementation(projects.google.tasks)
171171
implementation(projects.tasksAppShared)
172172

173+
"demoImplementation"(projects.tasksCore) {
174+
because("needed for prefilled content for screenshot generation")
175+
}
176+
173177
testImplementation(kotlin("test"))
174178
testImplementation(libs.koin.test)
175179
testImplementation(libs.ktor.client.core) {
9.6 KB
Loading
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
/*
2+
* Copyright (c) 2025 Olivier Patry
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining
5+
* a copy of this software and associated documentation files (the "Software"),
6+
* to deal in the Software without restriction, including without limitation
7+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+
* and/or sell copies of the Software, and to permit persons to whom the Software
9+
* is furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17+
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18+
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
20+
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
*/
22+
23+
package net.opatry.tasks.app.init
24+
25+
import android.app.Application
26+
import kotlinx.coroutines.Dispatchers
27+
import kotlinx.coroutines.runBlocking
28+
import kotlinx.coroutines.withContext
29+
import kotlinx.datetime.Clock
30+
import net.opatry.tasks.app.R
31+
import net.opatry.tasks.data.TaskDao
32+
import net.opatry.tasks.data.TaskListDao
33+
import net.opatry.tasks.data.UserDao
34+
import net.opatry.tasks.data.entity.TaskEntity
35+
import net.opatry.tasks.data.entity.TaskListEntity
36+
import net.opatry.tasks.data.entity.UserEntity
37+
import org.koin.android.ext.android.get
38+
import kotlin.time.Duration.Companion.days
39+
40+
object FlavorCustomInit {
41+
fun Application.init() {
42+
// TODO would be more elegant to use Room preloaded data mechanism.
43+
// Was tested but didn't work first time, not investigated a lot.
44+
// That being said, it's simpler to make evolution on pre-filled content programmatically.
45+
// see https://developer.android.com/training/data-storage/room/prepopulate
46+
val userDao = get<UserDao>()
47+
val taskListDao = get<TaskListDao>()
48+
val taskDao = get<TaskDao>()
49+
runBlocking {
50+
withContext(Dispatchers.Default) {
51+
userDao.setSignedInUser(
52+
UserEntity(
53+
remoteId = "demo",
54+
email = "[email protected]",
55+
name = "Jane Doe",
56+
avatarUrl = "file:///android_asset/avatar.png",
57+
isSignedIn = true,
58+
)
59+
)
60+
val myTasksListId = taskListDao.insert(
61+
TaskListEntity(
62+
title = getString(R.string.demo_task_list_default),
63+
lastUpdateDate = Clock.System.now(),
64+
sorting = TaskListEntity.Sorting.DueDate,
65+
)
66+
)
67+
taskDao.insert(
68+
TaskEntity(
69+
remoteId = "my_task1",
70+
title = getString(R.string.demo_task_list_default_task1),
71+
notes = getString(R.string.demo_task_list_default_task1_notes),
72+
parentListLocalId = myTasksListId,
73+
dueDate = Clock.System.now() + 1.days,
74+
lastUpdateDate = Clock.System.now(),
75+
position = "1",
76+
isCompleted = false,
77+
)
78+
)
79+
taskDao.insert(
80+
TaskEntity(
81+
remoteId = "my_task2",
82+
title = getString(R.string.demo_task_list_default_task2),
83+
parentListLocalId = myTasksListId,
84+
dueDate = Clock.System.now() - 1.days,
85+
lastUpdateDate = Clock.System.now(),
86+
position = "2",
87+
isCompleted = false,
88+
)
89+
)
90+
taskDao.insert(
91+
TaskEntity(
92+
remoteId = "my_task3",
93+
title = getString(R.string.demo_task_list_default_task3),
94+
notes = getString(R.string.demo_task_list_default_task3_notes),
95+
parentListLocalId = myTasksListId,
96+
dueDate = null,
97+
lastUpdateDate = Clock.System.now(),
98+
position = "3",
99+
isCompleted = true,
100+
completionDate = Clock.System.now() - 1.days,
101+
)
102+
)
103+
val groceriesListId = taskListDao.insert(
104+
TaskListEntity(
105+
title = getString(R.string.demo_task_list_groceries),
106+
lastUpdateDate = Clock.System.now(),
107+
sorting = TaskListEntity.Sorting.Title,
108+
)
109+
)
110+
taskDao.insert(
111+
TaskEntity(
112+
remoteId = "groceries_task1",
113+
title = getString(R.string.demo_task_list_groceries_task1),
114+
parentListLocalId = groceriesListId,
115+
dueDate = null,
116+
lastUpdateDate = Clock.System.now(),
117+
position = "1",
118+
isCompleted = false,
119+
)
120+
)
121+
taskDao.insert(
122+
TaskEntity(
123+
remoteId = "groceries_task2",
124+
title = getString(R.string.demo_task_list_groceries_task2),
125+
parentListLocalId = groceriesListId,
126+
dueDate = null,
127+
lastUpdateDate = Clock.System.now(),
128+
position = "2",
129+
isCompleted = false,
130+
)
131+
)
132+
taskDao.insert(
133+
TaskEntity(
134+
remoteId = "groceries_task3",
135+
title = getString(R.string.demo_task_list_groceries_task3),
136+
parentListLocalId = groceriesListId,
137+
dueDate = null,
138+
lastUpdateDate = Clock.System.now(),
139+
position = "3",
140+
isCompleted = true,
141+
completionDate = Clock.System.now() - 2.days,
142+
)
143+
)
144+
taskDao.insert(
145+
TaskEntity(
146+
remoteId = "groceries_task4",
147+
title = getString(R.string.demo_task_list_groceries_task4),
148+
parentListLocalId = groceriesListId,
149+
dueDate = null,
150+
lastUpdateDate = Clock.System.now(),
151+
position = "4",
152+
isCompleted = true,
153+
completionDate = Clock.System.now(),
154+
)
155+
)
156+
val homeListId = taskListDao.insert(
157+
TaskListEntity(
158+
title = getString(R.string.demo_task_list_home),
159+
lastUpdateDate = Clock.System.now(),
160+
sorting = TaskListEntity.Sorting.UserDefined,
161+
)
162+
)
163+
taskDao.insert(
164+
TaskEntity(
165+
remoteId = "home_task1",
166+
title = getString(R.string.demo_task_list_home_task1),
167+
parentListLocalId = homeListId,
168+
dueDate = null,
169+
lastUpdateDate = Clock.System.now(),
170+
position = "1",
171+
isCompleted = false,
172+
)
173+
)
174+
taskDao.insert(
175+
TaskEntity(
176+
remoteId = "home_task2",
177+
title = getString(R.string.demo_task_list_home_task2),
178+
parentListLocalId = homeListId,
179+
dueDate = null,
180+
lastUpdateDate = Clock.System.now(),
181+
position = "2",
182+
isCompleted = false,
183+
)
184+
)
185+
taskDao.insert(
186+
TaskEntity(
187+
remoteId = "home_task3",
188+
title = getString(R.string.demo_task_list_home_task3),
189+
notes = getString(R.string.demo_task_list_home_task3_notes),
190+
parentListLocalId = homeListId,
191+
dueDate = Clock.System.now() + 1.days,
192+
lastUpdateDate = Clock.System.now(),
193+
position = "3",
194+
isCompleted = false,
195+
)
196+
)
197+
val workListId = taskListDao.insert(
198+
TaskListEntity(
199+
title = getString(R.string.demo_task_list_work),
200+
lastUpdateDate = Clock.System.now(),
201+
sorting = TaskListEntity.Sorting.UserDefined,
202+
)
203+
)
204+
taskDao.insert(
205+
TaskEntity(
206+
remoteId = "work_task1",
207+
title = getString(R.string.demo_task_list_work_task1),
208+
notes = getString(R.string.demo_task_list_work_task1_notes),
209+
parentListLocalId = workListId,
210+
dueDate = Clock.System.now() - 1.days,
211+
lastUpdateDate = Clock.System.now(),
212+
position = "1",
213+
isCompleted = false,
214+
)
215+
)
216+
val teamMeetingTaskId = taskDao.insert(
217+
TaskEntity(
218+
remoteId = "work_task2",
219+
title = getString(R.string.demo_task_list_work_task2),
220+
notes = getString(R.string.demo_task_list_work_task2_notes),
221+
parentListLocalId = workListId,
222+
dueDate = Clock.System.now(),
223+
lastUpdateDate = Clock.System.now(),
224+
position = "2",
225+
isCompleted = false,
226+
)
227+
)
228+
taskDao.insert(
229+
TaskEntity(
230+
remoteId = "work_task3",
231+
title = getString(R.string.demo_task_list_work_task3),
232+
notes = getString(R.string.demo_task_list_work_task3_notes),
233+
parentListLocalId = workListId,
234+
parentTaskLocalId = teamMeetingTaskId,
235+
parentTaskRemoteId = "work_task2",
236+
dueDate = null,
237+
lastUpdateDate = Clock.System.now(),
238+
position = "1",
239+
isCompleted = false,
240+
)
241+
)
242+
}
243+
}
244+
}
245+
}

tasks-app-android/src/demo/res/values/strings.xml

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
Copyright (c) 2024 Olivier Patry
2+
Copyright (c) 2025 Olivier Patry
33
44
Permission is hereby granted, free of charge, to any person obtaining
55
a copy of this software and associated documentation files (the "Software"),
@@ -22,4 +22,29 @@
2222

2323
<resources>
2424
<string name="app_name">📸 Taskfolio</string>
25+
26+
<string name="demo_task_list_default">👩‍💼 My Tasks</string>
27+
<string name="demo_task_list_default_task1">Plan weekend getaway 🏖️</string>
28+
<string name="demo_task_list_default_task1_notes">"• Find accommodations\n• Check weather"️</string>
29+
<string name="demo_task_list_default_task2">Finish reading book 📖️</string>
30+
<string name="demo_task_list_default_task3">Organize desk 📁️</string>
31+
<string name="demo_task_list_default_task3_notes">"• Sort out papers\n• Set up new monitor"</string>
32+
<string name="demo_task_list_groceries">🛒 Groceries</string>
33+
<string name="demo_task_list_groceries_task1">Milk 🥛</string>
34+
<string name="demo_task_list_groceries_task2">Cheese 🧀</string>
35+
<string name="demo_task_list_groceries_task3">Carrots 🥕</string>
36+
<string name="demo_task_list_groceries_task4">Bread 🥖</string>
37+
<string name="demo_task_list_groceries_task4_notes">Whole wheat</string>
38+
<string name="demo_task_list_home">🏡 Home</string>
39+
<string name="demo_task_list_home_task1">Fix leaking faucet 🚰</string>
40+
<string name="demo_task_list_home_task2">Mow the lawn 🌱</string>
41+
<string name="demo_task_list_home_task3">Garage appointment 🛠️ 🚗</string>
42+
<string name="demo_task_list_home_task3_notes">"• Oil change\n• Check brakes…\n• Tire rotation"</string>
43+
<string name="demo_task_list_work">💼 Work</string>
44+
<string name="demo_task_list_work_task1">📑 Finish Acme report</string>
45+
<string name="demo_task_list_work_task1_notes">Include last quarter’s stats</string>
46+
<string name="demo_task_list_work_task2">Attend team meeting</string>
47+
<string name="demo_task_list_work_task2_notes">Discuss project timelines</string>
48+
<string name="demo_task_list_work_task3">Review project proposals</string>
49+
<string name="demo_task_list_work_task3_notes">Focus on budget analysis</string>
2550
</resources>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright (c) 2025 Olivier Patry
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining
5+
* a copy of this software and associated documentation files (the "Software"),
6+
* to deal in the Software without restriction, including without limitation
7+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+
* and/or sell copies of the Software, and to permit persons to whom the Software
9+
* is furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17+
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18+
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
20+
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
*/
22+
23+
package net.opatry.tasks.app.init
24+
25+
import android.app.Application
26+
27+
object FlavorCustomInit {
28+
fun Application.init() {
29+
// Nothing custom is needed for this flavor
30+
}
31+
}

tasks-app-android/src/main/java/net/opatry/tasks/app/TasksApplication.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import org.koin.android.ext.koin.androidContext
3434
import org.koin.androix.startup.KoinStartup
3535
import org.koin.core.annotation.KoinExperimentalAPI
3636
import org.koin.dsl.koinConfiguration
37+
import net.opatry.tasks.app.init.FlavorCustomInit.init as flavorInit
3738

3839
private const val GCP_CLIENT_ID = "191682949161-esokhlfh7uugqptqnu3su9vgqmvltv95.apps.googleusercontent.com"
3940

@@ -52,4 +53,10 @@ class TasksApplication : Application(), KoinStartup {
5253
tasksAppModule,
5354
)
5455
}
56+
57+
override fun onCreate() {
58+
super.onCreate()
59+
60+
flavorInit()
61+
}
5562
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright (c) 2025 Olivier Patry
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining
5+
* a copy of this software and associated documentation files (the "Software"),
6+
* to deal in the Software without restriction, including without limitation
7+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+
* and/or sell copies of the Software, and to permit persons to whom the Software
9+
* is furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17+
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18+
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
20+
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
*/
22+
23+
package net.opatry.tasks.app.init
24+
25+
import android.app.Application
26+
27+
object FlavorCustomInit {
28+
fun Application.init() {
29+
// Nothing custom is needed for this flavor
30+
}
31+
}

0 commit comments

Comments
 (0)