📱

[趣味開発]タスク管理通知アプリの開発 チェックリスト編

2024/10/13に公開

[趣味開発]タスク管理通知アプリの開発 チェックリスト編

はじめに

https://zenn.dev/articles/e7acefa7e634f8/edit
の続き

修正前


修正したいこと

・タスクをチェックリスト形式に変更
・タスク追加ボタンを表示
・タスクチェッククリアボタンを表示

修正後ソース

task_reminder_widget.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:background="#CCFFFFFF">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true"
        android:orientation="horizontal">

        <!-- + ボタン -->
        <ImageButton
            android:id="@+id/addTaskButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@android:drawable/ic_input_add"
            android:contentDescription="Add Task" />

        <!-- 全タスクのチェックを外すボタン -->
        <ImageButton
            android:id="@+id/clearAllTasksButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:src="@android:drawable/ic_menu_close_clear_cancel"
            android:contentDescription="Clear All Tasks" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/taskContainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_below="@id/addTaskButton"
        android:layout_marginTop="16dp" />

</RelativeLayout>

・TaskReminderWidget.kt

package com.example.taskreminder

import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.Paint
import android.widget.RemoteViews
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken

class TaskReminderWidget : AppWidgetProvider() {

    override fun onReceive(context: Context, intent: Intent) {
        super.onReceive(context, intent)

        if (intent.action == "TASK_COMPLETED") {
            val taskIndex = intent.getIntExtra("taskIndex", -1)
            if (taskIndex != -1) {
                val sharedPreferences = context.getSharedPreferences("TaskReminderPrefs", Context.MODE_PRIVATE)
                val completedTasks = getCompletedTasks(sharedPreferences)
                if (completedTasks.contains(taskIndex)) {
                    completedTasks.remove(taskIndex) // 取り消し線を解除
                } else {
                    completedTasks.add(taskIndex) // 取り消し線を追加
                }
                saveCompletedTasks(sharedPreferences, completedTasks)

                val appWidgetManager = AppWidgetManager.getInstance(context)
                val thisAppWidget = ComponentName(context.packageName, javaClass.name)
                val appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget)
                for (appWidgetId in appWidgetIds) {
                    updateAppWidget(context, appWidgetManager, appWidgetId)
                }
            }
        } else if (intent.action == "CLEAR_ALL_TASKS") {
            val sharedPreferences = context.getSharedPreferences("TaskReminderPrefs", Context.MODE_PRIVATE)
            saveCompletedTasks(sharedPreferences, mutableSetOf()) // 完了済みタスクリストをクリア

            val appWidgetManager = AppWidgetManager.getInstance(context)
            val thisAppWidget = ComponentName(context.packageName, javaClass.name)
            val appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget)
            for (appWidgetId in appWidgetIds) {
                updateAppWidget(context, appWidgetManager, appWidgetId)
            }
        }
    }

    override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
        for (appWidgetId in appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId)
        }
    }

    override fun onEnabled(context: Context) {}
    override fun onDisabled(context: Context) {}

    companion object {
        internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
            val views = RemoteViews(context.packageName, R.layout.task_reminder_widget)

            // SharedPreferencesからタスクリストを取得
            val sharedPreferences = context.getSharedPreferences("TaskReminderPrefs", Context.MODE_PRIVATE)
            val taskList = getTaskList(sharedPreferences)
            val completedTasks = getCompletedTasks(sharedPreferences)

            // タスクコンテナをクリアして、チェックボックスとタスクを追加
            views.removeAllViews(R.id.taskContainer)

            taskList.forEachIndexed { index, task ->
                // 各タスクごとにレイアウトを設定
                val taskView = RemoteViews(context.packageName, R.layout.task_item)
                taskView.setTextViewText(R.id.taskNameText, task)

                // タスクが完了済みの場合は取り消し線を追加
                if (completedTasks.contains(index)) {
                    taskView.setInt(R.id.taskNameText, "setPaintFlags", Paint.STRIKE_THRU_TEXT_FLAG)
                } else {
                    taskView.setInt(R.id.taskNameText, "setPaintFlags", 0)
                }

                // チェックボックスのPendingIntentを設定
                val intent = Intent(context, TaskReminderWidget::class.java)
                intent.action = "TASK_COMPLETED"
                intent.putExtra("taskIndex", index)
                val pendingIntent = PendingIntent.getBroadcast(context, index, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
                taskView.setOnClickPendingIntent(R.id.taskCheckBox, pendingIntent)

                // タスクコンテナに追加
                views.addView(R.id.taskContainer, taskView)
            }

            // + ボタンのインテントを設定
            val addTaskIntent = Intent(context, MainActivity::class.java)
            val addTaskPendingIntent = PendingIntent.getActivity(context, 0, addTaskIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
            views.setOnClickPendingIntent(R.id.addTaskButton, addTaskPendingIntent)

            // 全タスクのチェックを外すボタンのインテントを設定
            val clearAllTasksIntent = Intent(context, TaskReminderWidget::class.java)
            clearAllTasksIntent.action = "CLEAR_ALL_TASKS"
            val clearAllTasksPendingIntent = PendingIntent.getBroadcast(context, 0, clearAllTasksIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
            views.setOnClickPendingIntent(R.id.clearAllTasksButton, clearAllTasksPendingIntent)

            appWidgetManager.updateAppWidget(appWidgetId, views)
        }

        // タスクリストを取得
        fun getTaskList(sharedPreferences: SharedPreferences): MutableList<String> {
            val gson = Gson()
            val json = sharedPreferences.getString("taskList", null)
            val type = object : TypeToken<MutableList<String>>() {}.type
            return if (json != null) {
                gson.fromJson<MutableList<String>>(json, type) // 型を明示的に指定してオーバーロードの解決を助けます
            } else {
                mutableListOf()
            }
        }

        // 完了済みタスクリストを取得
        fun getCompletedTasks(sharedPreferences: SharedPreferences): MutableSet<Int> {
            return sharedPreferences.getStringSet("completedTasks", mutableSetOf())?.map { it.toInt() }?.toMutableSet() ?: mutableSetOf()
        }

        // 完了済みタスクリストを保存
        fun saveCompletedTasks(sharedPreferences: SharedPreferences, completedTasks: MutableSet<Int>) {
            val editor = sharedPreferences.edit()
            editor.putStringSet("completedTasks", completedTasks.map { it.toString() }.toSet())
            editor.apply()
        }
    }
}

修正後画面

タスク管理ウィジェットらしくなってきた

Discussion