Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
d3b7165
"Refactor: Entity/DAO from Item → Task, priority as String"
Max7414 May 11, 2025
39f8ef6
Fix override fun getAllTasksStream()
Max7414 May 11, 2025
5661c0d
app_name -> To Do List
Max7414 May 11, 2025
4513626
item->task_entry_title -> Add Task
Max7414 May 11, 2025
5b71005
item-> no_task_description -> Oops!\nNo tasks in the lists.\nTap + to…
Max7414 May 11, 2025
26f4b6f
HomeScreen.kt:
Max7414 May 11, 2025
855389a
HomeScreen.kt:
Max7414 May 11, 2025
9549b7d
strings.xml change all item to task.
Max7414 May 11, 2025
6c95997
more item to task refactor
Max7414 May 11, 2025
f9dac3b
task.q <0 remove
Max7414 May 11, 2025
7516cc2
Quinity to priority
Max7414 May 11, 2025
c160c8f
Preview edited
Max7414 May 11, 2025
dbdcee8
text = "WAITING TO BE REMOVE", locate
Max7414 May 11, 2025
160cd64
Runnable setting
Max7414 May 11, 2025
1110d3e
TaskEntryScreen.kt remove on coulumn
Max7414 May 11, 2025
3d07b32
price del
Max7414 May 11, 2025
7cf0ffe
Remove price coloumn
Max7414 May 11, 2025
d271a6b
UI changed
Max7414 May 11, 2025
a31f3b9
Add color system
Max7414 May 11, 2025
9bbd6ec
sell button remove
Max7414 May 11, 2025
0ff290c
Merge pull request #1 from Max7414/feature
Max7414 May 11, 2025
73bbecf
Radio Button done
Max7414 May 12, 2025
d9560de
Merge pull request #3 from Max7414/Priority-Level-RadioButton
Max7414 May 12, 2025
63d1128
add edit button
Max7414 May 12, 2025
981f796
增加disabled的輸入筐
Max7414 May 13, 2025
efc3efc
刪除按鈕位置調換
Max7414 May 13, 2025
c54f443
完成編輯功能
Max7414 May 13, 2025
c6ffa65
Merge pull request #4 from Max7414/Edit-Existing-Task
Max7414 May 13, 2025
991be78
add edit button
Max7414 May 12, 2025
7233e9f
增加disabled的輸入筐
Max7414 May 13, 2025
adee196
刪除按鈕位置調換
Max7414 May 13, 2025
d9b0ded
完成編輯功能
Max7414 May 13, 2025
e0e9c3c
加入swipe的依賴 加入滑動刪除功能
Max7414 May 13, 2025
b580e8e
Merge pull request #5 from Max7414/swipe-to-delete
Max7414 May 13, 2025
fc4d239
V.10 merge
Max7414 May 13, 2025
e83b626
增加readme.md
Max7414 May 14, 2025
4dc3406
DT-1 Adjust readme
Max7414 Sep 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 73 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,83 @@
Inventory app
TESTMESSAGE

To Do List app
==================================

Solution code for Android Basics with Compose.

Introduction

問題一
------------

This app is an Inventory tracking app. Demos how to add, update, sell, and delete items from the local database.
This app demonstrated the use of Android Jetpack component [Room](https://developer.android.com/training/data-storage/room) database.
The app also leverages [ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel),
[Flow](https://developer.android.com/kotlin/flow),
and [Navigation](https://developer.android.com/topic/libraries/architecture/navigation/).
*clone下來的存貨APP無法開啟*

Pre-requisites
--------------
## 解決方法

更改虛擬機的版本以及系統



## 問題二

*變數 函式名 檔案名在重構的過程中有許多問題 或是在修改後不能使用*

## 解決方法

用Git進行版本控制 在每個重大改變前先commit



## 問題三

*修改 Enity後程式運行會崩潰*

## 解決方法

查看log cat 找到崩潰原因

```kotlin
android.database.sqlite.SQLiteException: […]
no such column: priority (code 1 SQLITE_ERROR):
, while compiling: SELECT * FROM tasks ORDER BY name ASC
```

You need to know:
- How to create and use composables.
- How to navigate between composables, and pass data between them.
- How to use architecture components including ViewModel, Flow, StateFlow and StateUi.
- How to use coroutines for long-running tasks.
- SQLite database and the SQLite query language
詢問ChatGPT後是Room的語法問題

```kotlin
@Database(entities = [Task::class], version = 2, exportSchema = false)

Getting Started
---------------
//需要將version改成2
abstract class AppDatabase : RoomDatabase() {
// …
companion object {
fun create(context: Context): AppDatabase =
Room.databaseBuilder(context, AppDatabase::class.java, "app.db")
.fallbackToDestructiveMigration() // 直接砍掉舊 DB,重建新結構
.build()
}
}
```

1. Download and run the app.
## 問題四

*無法使用swipe元件*

## 解決方法

```kotlin
implementation("androidx.compose.material:material:1.8.1")
```

修改gradle檔 導入相依元件












--------------
4 changes: 3 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ dependencies {
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7")
implementation("androidx.navigation:navigation-compose:2.8.4")

implementation(platform("androidx.compose:compose-bom:2025.02.00"))
implementation("androidx.compose.material3:material3")
implementation("androidx.compose.material:material:1.8.1")
//Room
implementation("androidx.room:room-runtime:${rootProject.extra["room_version"]}")
implementation("androidx.core:core-ktx:1.15.0")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.example.inventory.data.InventoryDatabase
import com.example.inventory.data.Item
import com.example.inventory.data.ItemDao
import com.example.inventory.data.Task
import com.example.inventory.data.TaskDao
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
Expand All @@ -34,12 +34,12 @@ import org.junit.runner.RunWith
import java.io.IOException

@RunWith(AndroidJUnit4::class)
class ItemDaoTest {
class TaskDaoTest {

private lateinit var itemDao: ItemDao
private lateinit var taskDao: TaskDao
private lateinit var inventoryDatabase: InventoryDatabase
private val item1 = Item(1, "Apples", 10.0, 20)
private val item2 = Item(2, "Bananas", 15.0, 97)
private val task1 = Task(1, "Apples", 10.0, 20)
private val task2 = Task(2, "Bananas", 15.0, 97)

@Before
fun createDb() {
Expand All @@ -50,7 +50,7 @@ class ItemDaoTest {
// Allowing main thread queries, just for testing.
.allowMainThreadQueries()
.build()
itemDao = inventoryDatabase.itemDao()
taskDao = inventoryDatabase.taskDao()
}

@After
Expand All @@ -63,56 +63,56 @@ class ItemDaoTest {
@Throws(Exception::class)
fun daoInsert_insertsItemIntoDB() = runBlocking {
addOneItemToDb()
val allItems = itemDao.getAllItems().first()
assertEquals(allItems[0], item1)
val allItems = taskDao.getAllItems().first()
assertEquals(allItems[0], task1)
}

@Test
@Throws(Exception::class)
fun daoGetAllItems_returnsAllItemsFromDB() = runBlocking {
addTwoItemsToDb()
val allItems = itemDao.getAllItems().first()
assertEquals(allItems[0], item1)
assertEquals(allItems[1], item2)
val allItems = taskDao.getAllItems().first()
assertEquals(allItems[0], task1)
assertEquals(allItems[1], task2)
}


@Test
@Throws(Exception::class)
fun daoGetItem_returnsItemFromDB() = runBlocking {
addOneItemToDb()
val item = itemDao.getItem(1)
assertEquals(item.first(), item1)
val item = taskDao.getItem(1)
assertEquals(item.first(), task1)
}

@Test
@Throws(Exception::class)
fun daoDeleteItems_deletesAllItemsFromDB() = runBlocking {
addTwoItemsToDb()
itemDao.delete(item1)
itemDao.delete(item2)
val allItems = itemDao.getAllItems().first()
taskDao.delete(task1)
taskDao.delete(task2)
val allItems = taskDao.getAllItems().first()
assertTrue(allItems.isEmpty())
}

@Test
@Throws(Exception::class)
fun daoUpdateItems_updatesItemsInDB() = runBlocking {
addTwoItemsToDb()
itemDao.update(Item(1, "Apples", 15.0, 25))
itemDao.update(Item(2, "Bananas", 5.0, 50))
taskDao.update(Task(1, "Apples", 15.0, 25))
taskDao.update(Task(2, "Bananas", 5.0, 50))

val allItems = itemDao.getAllItems().first()
assertEquals(allItems[0], Item(1, "Apples", 15.0, 25))
assertEquals(allItems[1], Item(2, "Bananas", 5.0, 50))
val allItems = taskDao.getAllItems().first()
assertEquals(allItems[0], Task(1, "Apples", 15.0, 25))
assertEquals(allItems[1], Task(2, "Bananas", 5.0, 50))
}

private suspend fun addOneItemToDb() {
itemDao.insert(item1)
taskDao.insert(task1)
}

private suspend fun addTwoItemsToDb() {
itemDao.insert(item1)
itemDao.insert(item2)
taskDao.insert(task1)
taskDao.insert(task2)
}
}
10 changes: 5 additions & 5 deletions app/src/main/java/com/example/inventory/data/AppContainer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ import android.content.Context
* App container for Dependency injection.
*/
interface AppContainer {
val itemsRepository: ItemsRepository
val tasksRepository: TasksRepository
}

/**
* [AppContainer] implementation that provides instance of [OfflineItemsRepository]
* [AppContainer] implementation that provides instance of [OfflineTasksRepository]
*/
class AppDataContainer(private val context: Context) : AppContainer {
/**
* Implementation for [ItemsRepository]
* Implementation for [TasksRepository]
*/
override val itemsRepository: ItemsRepository by lazy {
OfflineItemsRepository(InventoryDatabase.getDatabase(context).itemDao())
override val tasksRepository: TasksRepository by lazy {
OfflineTasksRepository(InventoryDatabase.getDatabase(context).taskDao())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ import androidx.room.RoomDatabase
/**
* Database class with a singleton Instance object.
*/
@Database(entities = [Item::class], version = 1, exportSchema = false)
@Database(entities = [Task::class], version = 2, exportSchema = false)
abstract class InventoryDatabase : RoomDatabase() {

abstract fun itemDao(): ItemDao
abstract fun taskDao(): TaskDao

companion object {
@Volatile
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ package com.example.inventory.data

import kotlinx.coroutines.flow.Flow

class OfflineItemsRepository(private val itemDao: ItemDao) : ItemsRepository {
override fun getAllItemsStream(): Flow<List<Item>> = itemDao.getAllItems()
class OfflineTasksRepository(private val taskDao: TaskDao) : TasksRepository {
override fun getAllTasksStream(): Flow<List<Task>> = taskDao.getAllItems()

override fun getItemStream(id: Int): Flow<Item?> = itemDao.getItem(id)
override fun getTaskStream(id: Int): Flow<Task?> = taskDao.getItem(id)

override suspend fun insertItem(item: Item) = itemDao.insert(item)
override suspend fun insertTask(task: Task) = taskDao.insert(task)

override suspend fun deleteItem(item: Item) = itemDao.delete(item)
override suspend fun deleteTask(task: Task) = taskDao.delete(task)

override suspend fun updateItem(item: Item) = itemDao.update(item)
override suspend fun updateTask(task: Task) = taskDao.update(task)
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@ import androidx.room.PrimaryKey
/**
* Entity data class represents a single row in the database.
*/
@Entity(tableName = "items")
data class Item(
@Entity(tableName = "tasks")
data class Task(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
val name: String,
val price: Double,
val quantity: Int
val priority: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,22 @@ import kotlinx.coroutines.flow.Flow
* Database access object to access the Inventory database
*/
@Dao
interface ItemDao {
interface TaskDao {

@Query("SELECT * from items ORDER BY name ASC")
fun getAllItems(): Flow<List<Item>>
@Query("SELECT * from tasks ORDER BY name ASC")
fun getAllItems(): Flow<List<Task>>

@Query("SELECT * from items WHERE id = :id")
fun getItem(id: Int): Flow<Item>
@Query("SELECT * from tasks WHERE id = :id")
fun getItem(id: Int): Flow<Task>

// Specify the conflict strategy as IGNORE, when the user tries to add an
// existing Item into the database Room ignores the conflict.
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(item: Item)
suspend fun insert(task: Task)

@Update
suspend fun update(item: Item)
suspend fun update(task: Task)

@Delete
suspend fun delete(item: Item)
suspend fun delete(task: Task)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,31 @@ package com.example.inventory.data
import kotlinx.coroutines.flow.Flow

/**
* Repository that provides insert, update, delete, and retrieve of [Item] from a given data source.
* Repository that provides insert, update, delete, and retrieve of [Task] from a given data source.
*/
interface ItemsRepository {
interface TasksRepository {
/**
* Retrieve all the items from the the given data source.
*/
fun getAllItemsStream(): Flow<List<Item>>
fun getAllTasksStream(): Flow<List<Task>>

/**
* Retrieve an item from the given data source that matches with the [id].
*/
fun getItemStream(id: Int): Flow<Item?>
fun getTaskStream(id: Int): Flow<Task?>

/**
* Insert item in the data source
*/
suspend fun insertItem(item: Item)
suspend fun insertTask(task: Task)

/**
* Delete item from the data source
*/
suspend fun deleteItem(item: Item)
suspend fun deleteTask(task: Task)

/**
* Update item in the data source
*/
suspend fun updateItem(item: Item)
suspend fun updateTask(task: Task)
}
Loading