iT邦幫忙

2024 iThome 鐵人賽

DAY 17
0

前言

今天我們來弄最後剩下的代辦元件,順便把它結合GOOGLE Task,讓我們的APP可以讀取上面的資料

使用Google Tasks API

1.啟用Google Tasks API

我們回到之前啟用行事曆API服務的地方,和上次一樣,選擇API服務,並在搜尋找Google Tasks API並啟用他
https://ithelp.ithome.com.tw/upload/images/20241001/20162649zMGDcl97Dv.png
由於我們之前已經設定好了OAuth 2.0的憑證了,這次我們就不用再做一次,直接使用上次的平正要求TASK的權限就好。

2.添加build.gradle(APP)依賴項

啟用完api後我們要先去build.gradle(APP)添加google Tasks API的依賴項,讓我們能夠在程式中使
Google Tasks API

dependencies {
...
implementation("com.google.apis:google-api-services-tasks:v1-rev71-1.25.0")//Google Tasks API 依賴項
}

這時你如果直接執行程式碼可能會遇到下面的報錯

2 files found with path 'META-INF/INDEX.LIST'.
Adding a packaging block may help, please refer to
https://developer.android.com/reference/tools/gradle-api/8.6/com/android/build/api/dsl/Packaging
for more information

這是因為某些中有重複的文件,Android Studio會發生錯誤,遇到這種情況應該要去確認是甚麼依賴相沖,更換合適的api或確認不會衝突的版本,但我弄了一下午還是沒有解決,於是只能先讓Android Studio忽略重複項了,我們在build.gradle(APP)添加下面的程式碼。
程式碼如下。

packaging {
        resources {
            excludes += "META-INF/DEPENDENCIES"
            excludes += "META-INF/INDEX.LIST"
            excludes += "META-INF/*.kotlin_module"
        }
    }

3.建立GoogleTask.kt

然後我們建立一個新的kt檔來處理task相關的程式碼,程式碼如下

  • kotlin
package com.example.a2024ironman

import android.app.Activity
import android.util.Log
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.api.client.extensions.android.http.AndroidHttp
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential
import com.google.api.client.json.gson.GsonFactory
import com.google.api.services.tasks.Tasks
import com.google.api.services.tasks.TasksScopes
import com.google.api.services.tasks.model.Task
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import com.google.android.gms.auth.api.signin.GoogleSignInAccount

class GoogleTask(private val activity: Activity) {

    private var tasksService: Tasks? = null

    // 設定 Google Tasks 服務
    fun setupTasksService(account: GoogleSignInAccount?) {
        val credential = GoogleAccountCredential.usingOAuth2(
            activity, listOf(TasksScopes.TASKS)
        )
        credential.selectedAccount = account?.account
        tasksService = Tasks.Builder(
            AndroidHttp.newCompatibleTransport(),
            GsonFactory.getDefaultInstance(),
            credential
        ).setApplicationName("YourAppName").build()
    }

    // 獲取代辦事項
    fun fetchTasks(
        taskListId: String = "@default",
        onTasksFetched: (List<Task>) -> Unit,
        onError: (Exception) -> Unit
    ) {
        CoroutineScope(Dispatchers.IO).launch {
            try {
                val tasks = tasksService?.tasks()?.list(taskListId)?.execute()
                Log.d("GoogleTask", "Fetched tasks: ${tasks?.items?.size}")
                tasks?.items?.forEach {
                    Log.d("GoogleTask", "Task: ${it.title}")
                }
                withContext(Dispatchers.Main) {
                    onTasksFetched(tasks?.items ?: emptyList())
                }
            } catch (e: Exception) {
                Log.e("GoogleTask", "Error fetching tasks", e)
                withContext(Dispatchers.Main) {
                    onError(e)
                }
            }
        }
    }
}

3.修改GoogleCalendarAuth.kt

添加完程式碼後,我們回到之前的GoogleCalendarAuth.kt修改一下googleSignInClient,在裡面添加com.google.android.gms.common.api.Scope(TasksScopes.TASKS)讓我們再登入時請求task的權限。

  • kotlin
 private var googleSignInClient = GoogleSignIn.getClient(
        activity,
        GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestEmail()
            .requestScopes(
                com.google.android.gms.common.api.Scope(CalendarScopes.CALENDAR),
                com.google.android.gms.common.api.Scope(TasksScopes.TASKS)
            )
            .build()
    )

4.修改MainActivity.kt

最後我們修改主程式的程式碼,如下所示。

  • kotlin
class MainActivity : ComponentActivity() {
private var googleTask: GoogleTask? = null // 新增變數
private var tasks by mutableStateOf<List<Task>>(emptyList()) // 儲存代辦事項

...//原有程式碼

googleCalendarAuth = GoogleCalendarAuth(this) { success ->
            if (success) {
                Log.d("MainActivity", "Google Calendar Auth successful")

                // 開始同步 Google Calendar 事件
                googleCalendarAuth?.fetchEvents(
                    onEventsFetched = { events ->
                        calendarEvents = events
                        Log.d("MainActivity", "Fetched ${events.size} events from Google Calendar")
                    },
                    onError = { error ->
                        Log.e("MainActivity", "Error fetching calendar events: ${error.message}")
                    }
                )

                // 初始化 Google Tasks 服務
                googleTask = GoogleTask(this)
                googleTask?.setupTasksService(GoogleSignIn.getLastSignedInAccount(this))

                // 獲取 Google Tasks 代辦事項
                googleTask?.fetchTasks(
                    onTasksFetched = { taskList ->
                        tasks = taskList
                        Log.d("MainActivity", "Fetched ${taskList.size} tasks from Google Tasks")
                    },
                    onError = { error ->
                        Log.e("MainActivity", "Error fetching tasks: ${error.message}")
                    }
                )
            } else {
                Log.e("MainActivity", "Google Calendar Auth failed")
            }
        }

...//原有程式碼

fun CalendarLayout() {

...//原有程式碼

// 顯示代辦事項區塊
                Box(
                    modifier = Modifier
                        .weight(1f)
                        .fillMaxWidth()
                        .padding(4.dp)
                        .background(MaterialTheme.colorScheme.surface),
                    contentAlignment = Alignment.Center
                ) {

                    if (tasks.isNotEmpty()) {
                        Column {
                            tasks.forEach { task ->
                                Text(
                                    text = task.title ?: "無標題",
                                    style = TextStyle(
                                        fontSize = 16.sp,
                                        color = MaterialTheme.colorScheme.onSurface
                                    ),
                                    modifier = Modifier.padding(4.dp)
                                )
                            }
                        }
                    } else {
                        Text(
                            text = "無代辦事項",
                            style = TextStyle(
                                fontSize = 20.sp,
                                color = MaterialTheme.colorScheme.onSurface
                            )
                        )
                    }
                }

}

...//原有程式碼

上面都修改完後,原本代辦事項的box就會出現我們google task的資料了,為了測試,我在我的task裡建立了兩個代辦事件
https://ithelp.ithome.com.tw/upload/images/20241001/20162649VSbYiW3hea.png
app裡的呈現效果如下
https://ithelp.ithome.com.tw/upload/images/20241001/20162649IeUDMSGmJP.jpg
如果我們打勾完成了一個事件
https://ithelp.ithome.com.tw/upload/images/20241001/20162649NviiVyUy3F.png
在app中,該代辦事件就會消失,如下圖所示
https://ithelp.ithome.com.tw/upload/images/20241001/20162649EMhSRhGFvV.jpg

後話

今天初步完成了代辦元件結合GOOGLE Task的功能,明天來處理一下app的刷新,目前app刷新資料都要重新開啟app才會讀到最新的資料,這樣對於原本打算把它放在桌上當擺件的想法來說太麻煩了,每次都要重開,我還不如開google行事曆呢。那今天的內容就到這邊了,這幾天是颱風天,大家請注意安全不要去危險的地方,我們明天再見。


上一篇
Day16:單日行事曆UI介面的建構
下一篇
Day18:使用SwipeRefresh實作下拉刷新功能
系列文
github裡永遠有一個還沒做的SideProject :用Kotlin來開發點沒用的酷東西30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言