diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/DaoSession.java b/app/src/main/java/com/casic/br/greendao/DaoSession.java new file mode 100644 index 0000000..18d2242 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoSession.java @@ -0,0 +1,48 @@ +package com.casic.br.greendao; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.casic.br.model.LocaleMessageBean; + +import com.casic.br.greendao.LocaleMessageBeanDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig localeMessageBeanDaoConfig; + + private final LocaleMessageBeanDao localeMessageBeanDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + localeMessageBeanDaoConfig = daoConfigMap.get(LocaleMessageBeanDao.class).clone(); + localeMessageBeanDaoConfig.initIdentityScope(type); + + localeMessageBeanDao = new LocaleMessageBeanDao(localeMessageBeanDaoConfig, this); + + registerDao(LocaleMessageBean.class, localeMessageBeanDao); + } + + public void clear() { + localeMessageBeanDaoConfig.clearIdentityScope(); + } + + public LocaleMessageBeanDao getLocaleMessageBeanDao() { + return localeMessageBeanDao; + } + +} diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/DaoSession.java b/app/src/main/java/com/casic/br/greendao/DaoSession.java new file mode 100644 index 0000000..18d2242 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoSession.java @@ -0,0 +1,48 @@ +package com.casic.br.greendao; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.casic.br.model.LocaleMessageBean; + +import com.casic.br.greendao.LocaleMessageBeanDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig localeMessageBeanDaoConfig; + + private final LocaleMessageBeanDao localeMessageBeanDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + localeMessageBeanDaoConfig = daoConfigMap.get(LocaleMessageBeanDao.class).clone(); + localeMessageBeanDaoConfig.initIdentityScope(type); + + localeMessageBeanDao = new LocaleMessageBeanDao(localeMessageBeanDaoConfig, this); + + registerDao(LocaleMessageBean.class, localeMessageBeanDao); + } + + public void clear() { + localeMessageBeanDaoConfig.clearIdentityScope(); + } + + public LocaleMessageBeanDao getLocaleMessageBeanDao() { + return localeMessageBeanDao; + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java new file mode 100644 index 0000000..f41353a --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java @@ -0,0 +1,199 @@ +package com.casic.br.greendao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.Property; +import org.greenrobot.greendao.internal.DaoConfig; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseStatement; + +import com.casic.br.model.LocaleMessageBean; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table "LOCALE_MESSAGE_BEAN". +*/ +public class LocaleMessageBeanDao extends AbstractDao { + + public static final String TABLENAME = "LOCALE_MESSAGE_BEAN"; + + /** + * Properties of entity LocaleMessageBean.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property MessageId = new Property(1, String.class, "messageId", false, "MESSAGE_ID"); + public final static Property UserId = new Property(2, String.class, "userId", false, "USER_ID"); + public final static Property Title = new Property(3, String.class, "title", false, "TITLE"); + public final static Property Content = new Property(4, String.class, "content", false, "CONTENT"); + public final static Property MessageTime = new Property(5, String.class, "messageTime", false, "MESSAGE_TIME"); + public final static Property IsRead = new Property(6, String.class, "isRead", false, "IS_READ"); + } + + + public LocaleMessageBeanDao(DaoConfig config) { + super(config); + } + + public LocaleMessageBeanDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(Database db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "\"LOCALE_MESSAGE_BEAN\" (" + // + "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "\"MESSAGE_ID\" TEXT UNIQUE ," + // 1: messageId + "\"USER_ID\" TEXT," + // 2: userId + "\"TITLE\" TEXT," + // 3: title + "\"CONTENT\" TEXT," + // 4: content + "\"MESSAGE_TIME\" TEXT," + // 5: messageTime + "\"IS_READ\" TEXT);"); // 6: isRead + } + + /** Drops the underlying database table. */ + public static void dropTable(Database db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"LOCALE_MESSAGE_BEAN\""; + db.execSQL(sql); + } + + @Override + protected final void bindValues(DatabaseStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + protected final void bindValues(SQLiteStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + @Override + public LocaleMessageBean readEntity(Cursor cursor, int offset) { + LocaleMessageBean entity = new LocaleMessageBean( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // messageId + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // userId + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // title + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // content + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // messageTime + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6) // isRead + ); + return entity; + } + + @Override + public void readEntity(Cursor cursor, LocaleMessageBean entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setMessageId(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); + entity.setUserId(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); + entity.setTitle(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); + entity.setContent(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); + entity.setMessageTime(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); + entity.setIsRead(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); + } + + @Override + protected final Long updateKeyAfterInsert(LocaleMessageBean entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + @Override + public Long getKey(LocaleMessageBean entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + @Override + public boolean hasKey(LocaleMessageBean entity) { + return entity.getId() != null; + } + + @Override + protected final boolean isEntityUpdateable() { + return true; + } + +} diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/DaoSession.java b/app/src/main/java/com/casic/br/greendao/DaoSession.java new file mode 100644 index 0000000..18d2242 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoSession.java @@ -0,0 +1,48 @@ +package com.casic.br.greendao; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.casic.br.model.LocaleMessageBean; + +import com.casic.br.greendao.LocaleMessageBeanDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig localeMessageBeanDaoConfig; + + private final LocaleMessageBeanDao localeMessageBeanDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + localeMessageBeanDaoConfig = daoConfigMap.get(LocaleMessageBeanDao.class).clone(); + localeMessageBeanDaoConfig.initIdentityScope(type); + + localeMessageBeanDao = new LocaleMessageBeanDao(localeMessageBeanDaoConfig, this); + + registerDao(LocaleMessageBean.class, localeMessageBeanDao); + } + + public void clear() { + localeMessageBeanDaoConfig.clearIdentityScope(); + } + + public LocaleMessageBeanDao getLocaleMessageBeanDao() { + return localeMessageBeanDao; + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java new file mode 100644 index 0000000..f41353a --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java @@ -0,0 +1,199 @@ +package com.casic.br.greendao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.Property; +import org.greenrobot.greendao.internal.DaoConfig; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseStatement; + +import com.casic.br.model.LocaleMessageBean; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table "LOCALE_MESSAGE_BEAN". +*/ +public class LocaleMessageBeanDao extends AbstractDao { + + public static final String TABLENAME = "LOCALE_MESSAGE_BEAN"; + + /** + * Properties of entity LocaleMessageBean.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property MessageId = new Property(1, String.class, "messageId", false, "MESSAGE_ID"); + public final static Property UserId = new Property(2, String.class, "userId", false, "USER_ID"); + public final static Property Title = new Property(3, String.class, "title", false, "TITLE"); + public final static Property Content = new Property(4, String.class, "content", false, "CONTENT"); + public final static Property MessageTime = new Property(5, String.class, "messageTime", false, "MESSAGE_TIME"); + public final static Property IsRead = new Property(6, String.class, "isRead", false, "IS_READ"); + } + + + public LocaleMessageBeanDao(DaoConfig config) { + super(config); + } + + public LocaleMessageBeanDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(Database db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "\"LOCALE_MESSAGE_BEAN\" (" + // + "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "\"MESSAGE_ID\" TEXT UNIQUE ," + // 1: messageId + "\"USER_ID\" TEXT," + // 2: userId + "\"TITLE\" TEXT," + // 3: title + "\"CONTENT\" TEXT," + // 4: content + "\"MESSAGE_TIME\" TEXT," + // 5: messageTime + "\"IS_READ\" TEXT);"); // 6: isRead + } + + /** Drops the underlying database table. */ + public static void dropTable(Database db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"LOCALE_MESSAGE_BEAN\""; + db.execSQL(sql); + } + + @Override + protected final void bindValues(DatabaseStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + protected final void bindValues(SQLiteStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + @Override + public LocaleMessageBean readEntity(Cursor cursor, int offset) { + LocaleMessageBean entity = new LocaleMessageBean( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // messageId + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // userId + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // title + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // content + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // messageTime + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6) // isRead + ); + return entity; + } + + @Override + public void readEntity(Cursor cursor, LocaleMessageBean entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setMessageId(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); + entity.setUserId(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); + entity.setTitle(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); + entity.setContent(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); + entity.setMessageTime(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); + entity.setIsRead(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); + } + + @Override + protected final Long updateKeyAfterInsert(LocaleMessageBean entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + @Override + public Long getKey(LocaleMessageBean entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + @Override + public boolean hasKey(LocaleMessageBean entity) { + return entity.getId() != null; + } + + @Override + protected final boolean isEntityUpdateable() { + return true; + } + +} diff --git a/app/src/main/java/com/casic/br/model/LocaleMessageBean.java b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java new file mode 100644 index 0000000..1341da6 --- /dev/null +++ b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java @@ -0,0 +1,92 @@ +package com.casic.br.model; + +import org.greenrobot.greendao.annotation.Entity; +import org.greenrobot.greendao.annotation.Generated; +import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.Unique; + +@Entity +public class LocaleMessageBean { + @Id(autoincrement = true) + private Long id;//主键自增 + + @Unique + private String messageId; + private String userId; + private String title; + private String content; + private String messageTime; + private String isRead;//0-未读,1-已读 + + @Generated(hash = 22572871) + public LocaleMessageBean(Long id, String messageId, String userId, String title, + String content, String messageTime, String isRead) { + this.id = id; + this.messageId = messageId; + this.userId = userId; + this.title = title; + this.content = content; + this.messageTime = messageTime; + this.isRead = isRead; + } + + @Generated(hash = 1114477439) + public LocaleMessageBean() { + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMessageId() { + return this.messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getUserId() { + return this.userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMessageTime() { + return this.messageTime; + } + + public void setMessageTime(String messageTime) { + this.messageTime = messageTime; + } + + public String getIsRead() { + return this.isRead; + } + + public void setIsRead(String isRead) { + this.isRead = isRead; + } +} diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/DaoSession.java b/app/src/main/java/com/casic/br/greendao/DaoSession.java new file mode 100644 index 0000000..18d2242 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoSession.java @@ -0,0 +1,48 @@ +package com.casic.br.greendao; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.casic.br.model.LocaleMessageBean; + +import com.casic.br.greendao.LocaleMessageBeanDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig localeMessageBeanDaoConfig; + + private final LocaleMessageBeanDao localeMessageBeanDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + localeMessageBeanDaoConfig = daoConfigMap.get(LocaleMessageBeanDao.class).clone(); + localeMessageBeanDaoConfig.initIdentityScope(type); + + localeMessageBeanDao = new LocaleMessageBeanDao(localeMessageBeanDaoConfig, this); + + registerDao(LocaleMessageBean.class, localeMessageBeanDao); + } + + public void clear() { + localeMessageBeanDaoConfig.clearIdentityScope(); + } + + public LocaleMessageBeanDao getLocaleMessageBeanDao() { + return localeMessageBeanDao; + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java new file mode 100644 index 0000000..f41353a --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java @@ -0,0 +1,199 @@ +package com.casic.br.greendao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.Property; +import org.greenrobot.greendao.internal.DaoConfig; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseStatement; + +import com.casic.br.model.LocaleMessageBean; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table "LOCALE_MESSAGE_BEAN". +*/ +public class LocaleMessageBeanDao extends AbstractDao { + + public static final String TABLENAME = "LOCALE_MESSAGE_BEAN"; + + /** + * Properties of entity LocaleMessageBean.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property MessageId = new Property(1, String.class, "messageId", false, "MESSAGE_ID"); + public final static Property UserId = new Property(2, String.class, "userId", false, "USER_ID"); + public final static Property Title = new Property(3, String.class, "title", false, "TITLE"); + public final static Property Content = new Property(4, String.class, "content", false, "CONTENT"); + public final static Property MessageTime = new Property(5, String.class, "messageTime", false, "MESSAGE_TIME"); + public final static Property IsRead = new Property(6, String.class, "isRead", false, "IS_READ"); + } + + + public LocaleMessageBeanDao(DaoConfig config) { + super(config); + } + + public LocaleMessageBeanDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(Database db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "\"LOCALE_MESSAGE_BEAN\" (" + // + "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "\"MESSAGE_ID\" TEXT UNIQUE ," + // 1: messageId + "\"USER_ID\" TEXT," + // 2: userId + "\"TITLE\" TEXT," + // 3: title + "\"CONTENT\" TEXT," + // 4: content + "\"MESSAGE_TIME\" TEXT," + // 5: messageTime + "\"IS_READ\" TEXT);"); // 6: isRead + } + + /** Drops the underlying database table. */ + public static void dropTable(Database db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"LOCALE_MESSAGE_BEAN\""; + db.execSQL(sql); + } + + @Override + protected final void bindValues(DatabaseStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + protected final void bindValues(SQLiteStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + @Override + public LocaleMessageBean readEntity(Cursor cursor, int offset) { + LocaleMessageBean entity = new LocaleMessageBean( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // messageId + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // userId + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // title + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // content + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // messageTime + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6) // isRead + ); + return entity; + } + + @Override + public void readEntity(Cursor cursor, LocaleMessageBean entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setMessageId(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); + entity.setUserId(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); + entity.setTitle(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); + entity.setContent(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); + entity.setMessageTime(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); + entity.setIsRead(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); + } + + @Override + protected final Long updateKeyAfterInsert(LocaleMessageBean entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + @Override + public Long getKey(LocaleMessageBean entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + @Override + public boolean hasKey(LocaleMessageBean entity) { + return entity.getId() != null; + } + + @Override + protected final boolean isEntityUpdateable() { + return true; + } + +} diff --git a/app/src/main/java/com/casic/br/model/LocaleMessageBean.java b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java new file mode 100644 index 0000000..1341da6 --- /dev/null +++ b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java @@ -0,0 +1,92 @@ +package com.casic.br.model; + +import org.greenrobot.greendao.annotation.Entity; +import org.greenrobot.greendao.annotation.Generated; +import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.Unique; + +@Entity +public class LocaleMessageBean { + @Id(autoincrement = true) + private Long id;//主键自增 + + @Unique + private String messageId; + private String userId; + private String title; + private String content; + private String messageTime; + private String isRead;//0-未读,1-已读 + + @Generated(hash = 22572871) + public LocaleMessageBean(Long id, String messageId, String userId, String title, + String content, String messageTime, String isRead) { + this.id = id; + this.messageId = messageId; + this.userId = userId; + this.title = title; + this.content = content; + this.messageTime = messageTime; + this.isRead = isRead; + } + + @Generated(hash = 1114477439) + public LocaleMessageBean() { + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMessageId() { + return this.messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getUserId() { + return this.userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMessageTime() { + return this.messageTime; + } + + public void setMessageTime(String messageTime) { + this.messageTime = messageTime; + } + + public String getIsRead() { + return this.isRead; + } + + public void setIsRead(String isRead) { + this.isRead = isRead; + } +} diff --git a/app/src/main/java/com/casic/br/utils/BadeHelper.kt b/app/src/main/java/com/casic/br/utils/BadeHelper.kt new file mode 100644 index 0000000..2db01eb --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/BadeHelper.kt @@ -0,0 +1,14 @@ +package com.casic.br.utils + +import android.content.Context +import me.leolin.shortcutbadger.ShortcutBadger + +object BadeHelper { + fun setBadgeNum(context: Context, badgeCount: Int) { + if (badgeCount == 0) { + ShortcutBadger.removeCount(context) + } else { + ShortcutBadger.applyCount(context, badgeCount) + } + } +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/DaoSession.java b/app/src/main/java/com/casic/br/greendao/DaoSession.java new file mode 100644 index 0000000..18d2242 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoSession.java @@ -0,0 +1,48 @@ +package com.casic.br.greendao; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.casic.br.model.LocaleMessageBean; + +import com.casic.br.greendao.LocaleMessageBeanDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig localeMessageBeanDaoConfig; + + private final LocaleMessageBeanDao localeMessageBeanDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + localeMessageBeanDaoConfig = daoConfigMap.get(LocaleMessageBeanDao.class).clone(); + localeMessageBeanDaoConfig.initIdentityScope(type); + + localeMessageBeanDao = new LocaleMessageBeanDao(localeMessageBeanDaoConfig, this); + + registerDao(LocaleMessageBean.class, localeMessageBeanDao); + } + + public void clear() { + localeMessageBeanDaoConfig.clearIdentityScope(); + } + + public LocaleMessageBeanDao getLocaleMessageBeanDao() { + return localeMessageBeanDao; + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java new file mode 100644 index 0000000..f41353a --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java @@ -0,0 +1,199 @@ +package com.casic.br.greendao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.Property; +import org.greenrobot.greendao.internal.DaoConfig; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseStatement; + +import com.casic.br.model.LocaleMessageBean; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table "LOCALE_MESSAGE_BEAN". +*/ +public class LocaleMessageBeanDao extends AbstractDao { + + public static final String TABLENAME = "LOCALE_MESSAGE_BEAN"; + + /** + * Properties of entity LocaleMessageBean.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property MessageId = new Property(1, String.class, "messageId", false, "MESSAGE_ID"); + public final static Property UserId = new Property(2, String.class, "userId", false, "USER_ID"); + public final static Property Title = new Property(3, String.class, "title", false, "TITLE"); + public final static Property Content = new Property(4, String.class, "content", false, "CONTENT"); + public final static Property MessageTime = new Property(5, String.class, "messageTime", false, "MESSAGE_TIME"); + public final static Property IsRead = new Property(6, String.class, "isRead", false, "IS_READ"); + } + + + public LocaleMessageBeanDao(DaoConfig config) { + super(config); + } + + public LocaleMessageBeanDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(Database db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "\"LOCALE_MESSAGE_BEAN\" (" + // + "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "\"MESSAGE_ID\" TEXT UNIQUE ," + // 1: messageId + "\"USER_ID\" TEXT," + // 2: userId + "\"TITLE\" TEXT," + // 3: title + "\"CONTENT\" TEXT," + // 4: content + "\"MESSAGE_TIME\" TEXT," + // 5: messageTime + "\"IS_READ\" TEXT);"); // 6: isRead + } + + /** Drops the underlying database table. */ + public static void dropTable(Database db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"LOCALE_MESSAGE_BEAN\""; + db.execSQL(sql); + } + + @Override + protected final void bindValues(DatabaseStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + protected final void bindValues(SQLiteStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + @Override + public LocaleMessageBean readEntity(Cursor cursor, int offset) { + LocaleMessageBean entity = new LocaleMessageBean( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // messageId + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // userId + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // title + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // content + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // messageTime + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6) // isRead + ); + return entity; + } + + @Override + public void readEntity(Cursor cursor, LocaleMessageBean entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setMessageId(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); + entity.setUserId(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); + entity.setTitle(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); + entity.setContent(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); + entity.setMessageTime(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); + entity.setIsRead(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); + } + + @Override + protected final Long updateKeyAfterInsert(LocaleMessageBean entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + @Override + public Long getKey(LocaleMessageBean entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + @Override + public boolean hasKey(LocaleMessageBean entity) { + return entity.getId() != null; + } + + @Override + protected final boolean isEntityUpdateable() { + return true; + } + +} diff --git a/app/src/main/java/com/casic/br/model/LocaleMessageBean.java b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java new file mode 100644 index 0000000..1341da6 --- /dev/null +++ b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java @@ -0,0 +1,92 @@ +package com.casic.br.model; + +import org.greenrobot.greendao.annotation.Entity; +import org.greenrobot.greendao.annotation.Generated; +import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.Unique; + +@Entity +public class LocaleMessageBean { + @Id(autoincrement = true) + private Long id;//主键自增 + + @Unique + private String messageId; + private String userId; + private String title; + private String content; + private String messageTime; + private String isRead;//0-未读,1-已读 + + @Generated(hash = 22572871) + public LocaleMessageBean(Long id, String messageId, String userId, String title, + String content, String messageTime, String isRead) { + this.id = id; + this.messageId = messageId; + this.userId = userId; + this.title = title; + this.content = content; + this.messageTime = messageTime; + this.isRead = isRead; + } + + @Generated(hash = 1114477439) + public LocaleMessageBean() { + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMessageId() { + return this.messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getUserId() { + return this.userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMessageTime() { + return this.messageTime; + } + + public void setMessageTime(String messageTime) { + this.messageTime = messageTime; + } + + public String getIsRead() { + return this.isRead; + } + + public void setIsRead(String isRead) { + this.isRead = isRead; + } +} diff --git a/app/src/main/java/com/casic/br/utils/BadeHelper.kt b/app/src/main/java/com/casic/br/utils/BadeHelper.kt new file mode 100644 index 0000000..2db01eb --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/BadeHelper.kt @@ -0,0 +1,14 @@ +package com.casic.br.utils + +import android.content.Context +import me.leolin.shortcutbadger.ShortcutBadger + +object BadeHelper { + fun setBadgeNum(context: Context, badgeCount: Int) { + if (badgeCount == 0) { + ShortcutBadger.removeCount(context) + } else { + ShortcutBadger.applyCount(context, badgeCount) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/DataBaseManager.kt b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt new file mode 100644 index 0000000..3918b77 --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt @@ -0,0 +1,69 @@ +package com.casic.br.utils + +import com.casic.br.base.BaseApplication +import com.casic.br.greendao.LocaleMessageBeanDao +import com.casic.br.model.LocaleMessageBean + +class DataBaseManager private constructor() { + + companion object { + //Kotlin委托模式双重锁单例 + val instance: DataBaseManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + DataBaseManager() + } + } + + private val beanDao = BaseApplication.obtainInstance().obtainDaoSession().localeMessageBeanDao + + fun insertLocaleMessage( + messageId: String, userId: String, title: String, + content: String, isRead: String, messageTime: String + ) { + val messageBean = LocaleMessageBean() + messageBean.messageId = messageId + messageBean.userId = userId + messageBean.title = title + messageBean.content = content + messageBean.isRead = isRead + messageBean.messageTime = messageTime + beanDao.insert(messageBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun deleteLocaleMessageById(userId: String, messageId: String) { + val result = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).list() + beanDao.deleteInTx(result) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun updateLocaleMessageById(userId: String, messageId: String) { + val noticeLocaleBean = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).unique() ?: return + noticeLocaleBean.isRead = "1" + beanDao.update(noticeLocaleBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + + fun queryMessageByPage(userId: String, offset: Int): MutableList { + return BaseApplication.obtainInstance().obtainDaoSession() + .queryBuilder(LocaleMessageBean::class.java) + .where(LocaleMessageBeanDao.Properties.UserId.eq(userId)) + .offset(offset * LocaleConstant.PAGE_LIMIT) + .orderDesc(LocaleMessageBeanDao.Properties.MessageTime) + .limit(LocaleConstant.PAGE_LIMIT) + .list() + } + + private fun queryUnReadMessage(): Int { + return beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.IsRead.eq("0") + ).list().size + } +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/DaoSession.java b/app/src/main/java/com/casic/br/greendao/DaoSession.java new file mode 100644 index 0000000..18d2242 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoSession.java @@ -0,0 +1,48 @@ +package com.casic.br.greendao; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.casic.br.model.LocaleMessageBean; + +import com.casic.br.greendao.LocaleMessageBeanDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig localeMessageBeanDaoConfig; + + private final LocaleMessageBeanDao localeMessageBeanDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + localeMessageBeanDaoConfig = daoConfigMap.get(LocaleMessageBeanDao.class).clone(); + localeMessageBeanDaoConfig.initIdentityScope(type); + + localeMessageBeanDao = new LocaleMessageBeanDao(localeMessageBeanDaoConfig, this); + + registerDao(LocaleMessageBean.class, localeMessageBeanDao); + } + + public void clear() { + localeMessageBeanDaoConfig.clearIdentityScope(); + } + + public LocaleMessageBeanDao getLocaleMessageBeanDao() { + return localeMessageBeanDao; + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java new file mode 100644 index 0000000..f41353a --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java @@ -0,0 +1,199 @@ +package com.casic.br.greendao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.Property; +import org.greenrobot.greendao.internal.DaoConfig; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseStatement; + +import com.casic.br.model.LocaleMessageBean; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table "LOCALE_MESSAGE_BEAN". +*/ +public class LocaleMessageBeanDao extends AbstractDao { + + public static final String TABLENAME = "LOCALE_MESSAGE_BEAN"; + + /** + * Properties of entity LocaleMessageBean.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property MessageId = new Property(1, String.class, "messageId", false, "MESSAGE_ID"); + public final static Property UserId = new Property(2, String.class, "userId", false, "USER_ID"); + public final static Property Title = new Property(3, String.class, "title", false, "TITLE"); + public final static Property Content = new Property(4, String.class, "content", false, "CONTENT"); + public final static Property MessageTime = new Property(5, String.class, "messageTime", false, "MESSAGE_TIME"); + public final static Property IsRead = new Property(6, String.class, "isRead", false, "IS_READ"); + } + + + public LocaleMessageBeanDao(DaoConfig config) { + super(config); + } + + public LocaleMessageBeanDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(Database db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "\"LOCALE_MESSAGE_BEAN\" (" + // + "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "\"MESSAGE_ID\" TEXT UNIQUE ," + // 1: messageId + "\"USER_ID\" TEXT," + // 2: userId + "\"TITLE\" TEXT," + // 3: title + "\"CONTENT\" TEXT," + // 4: content + "\"MESSAGE_TIME\" TEXT," + // 5: messageTime + "\"IS_READ\" TEXT);"); // 6: isRead + } + + /** Drops the underlying database table. */ + public static void dropTable(Database db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"LOCALE_MESSAGE_BEAN\""; + db.execSQL(sql); + } + + @Override + protected final void bindValues(DatabaseStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + protected final void bindValues(SQLiteStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + @Override + public LocaleMessageBean readEntity(Cursor cursor, int offset) { + LocaleMessageBean entity = new LocaleMessageBean( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // messageId + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // userId + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // title + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // content + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // messageTime + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6) // isRead + ); + return entity; + } + + @Override + public void readEntity(Cursor cursor, LocaleMessageBean entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setMessageId(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); + entity.setUserId(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); + entity.setTitle(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); + entity.setContent(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); + entity.setMessageTime(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); + entity.setIsRead(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); + } + + @Override + protected final Long updateKeyAfterInsert(LocaleMessageBean entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + @Override + public Long getKey(LocaleMessageBean entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + @Override + public boolean hasKey(LocaleMessageBean entity) { + return entity.getId() != null; + } + + @Override + protected final boolean isEntityUpdateable() { + return true; + } + +} diff --git a/app/src/main/java/com/casic/br/model/LocaleMessageBean.java b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java new file mode 100644 index 0000000..1341da6 --- /dev/null +++ b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java @@ -0,0 +1,92 @@ +package com.casic.br.model; + +import org.greenrobot.greendao.annotation.Entity; +import org.greenrobot.greendao.annotation.Generated; +import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.Unique; + +@Entity +public class LocaleMessageBean { + @Id(autoincrement = true) + private Long id;//主键自增 + + @Unique + private String messageId; + private String userId; + private String title; + private String content; + private String messageTime; + private String isRead;//0-未读,1-已读 + + @Generated(hash = 22572871) + public LocaleMessageBean(Long id, String messageId, String userId, String title, + String content, String messageTime, String isRead) { + this.id = id; + this.messageId = messageId; + this.userId = userId; + this.title = title; + this.content = content; + this.messageTime = messageTime; + this.isRead = isRead; + } + + @Generated(hash = 1114477439) + public LocaleMessageBean() { + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMessageId() { + return this.messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getUserId() { + return this.userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMessageTime() { + return this.messageTime; + } + + public void setMessageTime(String messageTime) { + this.messageTime = messageTime; + } + + public String getIsRead() { + return this.isRead; + } + + public void setIsRead(String isRead) { + this.isRead = isRead; + } +} diff --git a/app/src/main/java/com/casic/br/utils/BadeHelper.kt b/app/src/main/java/com/casic/br/utils/BadeHelper.kt new file mode 100644 index 0000000..2db01eb --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/BadeHelper.kt @@ -0,0 +1,14 @@ +package com.casic.br.utils + +import android.content.Context +import me.leolin.shortcutbadger.ShortcutBadger + +object BadeHelper { + fun setBadgeNum(context: Context, badgeCount: Int) { + if (badgeCount == 0) { + ShortcutBadger.removeCount(context) + } else { + ShortcutBadger.applyCount(context, badgeCount) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/DataBaseManager.kt b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt new file mode 100644 index 0000000..3918b77 --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt @@ -0,0 +1,69 @@ +package com.casic.br.utils + +import com.casic.br.base.BaseApplication +import com.casic.br.greendao.LocaleMessageBeanDao +import com.casic.br.model.LocaleMessageBean + +class DataBaseManager private constructor() { + + companion object { + //Kotlin委托模式双重锁单例 + val instance: DataBaseManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + DataBaseManager() + } + } + + private val beanDao = BaseApplication.obtainInstance().obtainDaoSession().localeMessageBeanDao + + fun insertLocaleMessage( + messageId: String, userId: String, title: String, + content: String, isRead: String, messageTime: String + ) { + val messageBean = LocaleMessageBean() + messageBean.messageId = messageId + messageBean.userId = userId + messageBean.title = title + messageBean.content = content + messageBean.isRead = isRead + messageBean.messageTime = messageTime + beanDao.insert(messageBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun deleteLocaleMessageById(userId: String, messageId: String) { + val result = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).list() + beanDao.deleteInTx(result) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun updateLocaleMessageById(userId: String, messageId: String) { + val noticeLocaleBean = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).unique() ?: return + noticeLocaleBean.isRead = "1" + beanDao.update(noticeLocaleBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + + fun queryMessageByPage(userId: String, offset: Int): MutableList { + return BaseApplication.obtainInstance().obtainDaoSession() + .queryBuilder(LocaleMessageBean::class.java) + .where(LocaleMessageBeanDao.Properties.UserId.eq(userId)) + .offset(offset * LocaleConstant.PAGE_LIMIT) + .orderDesc(LocaleMessageBeanDao.Properties.MessageTime) + .limit(LocaleConstant.PAGE_LIMIT) + .list() + } + + private fun queryUnReadMessage(): Int { + return beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.IsRead.eq("0") + ).list().size + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt index 737e859..3b8dc98 100644 --- a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt @@ -35,6 +35,7 @@ * ============================================================================================= * */ const val PERMISSIONS_CODE = 999 + const val PAGE_LIMIT = 20 /** * ============================================================================================= diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/DaoSession.java b/app/src/main/java/com/casic/br/greendao/DaoSession.java new file mode 100644 index 0000000..18d2242 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoSession.java @@ -0,0 +1,48 @@ +package com.casic.br.greendao; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.casic.br.model.LocaleMessageBean; + +import com.casic.br.greendao.LocaleMessageBeanDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig localeMessageBeanDaoConfig; + + private final LocaleMessageBeanDao localeMessageBeanDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + localeMessageBeanDaoConfig = daoConfigMap.get(LocaleMessageBeanDao.class).clone(); + localeMessageBeanDaoConfig.initIdentityScope(type); + + localeMessageBeanDao = new LocaleMessageBeanDao(localeMessageBeanDaoConfig, this); + + registerDao(LocaleMessageBean.class, localeMessageBeanDao); + } + + public void clear() { + localeMessageBeanDaoConfig.clearIdentityScope(); + } + + public LocaleMessageBeanDao getLocaleMessageBeanDao() { + return localeMessageBeanDao; + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java new file mode 100644 index 0000000..f41353a --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java @@ -0,0 +1,199 @@ +package com.casic.br.greendao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.Property; +import org.greenrobot.greendao.internal.DaoConfig; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseStatement; + +import com.casic.br.model.LocaleMessageBean; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table "LOCALE_MESSAGE_BEAN". +*/ +public class LocaleMessageBeanDao extends AbstractDao { + + public static final String TABLENAME = "LOCALE_MESSAGE_BEAN"; + + /** + * Properties of entity LocaleMessageBean.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property MessageId = new Property(1, String.class, "messageId", false, "MESSAGE_ID"); + public final static Property UserId = new Property(2, String.class, "userId", false, "USER_ID"); + public final static Property Title = new Property(3, String.class, "title", false, "TITLE"); + public final static Property Content = new Property(4, String.class, "content", false, "CONTENT"); + public final static Property MessageTime = new Property(5, String.class, "messageTime", false, "MESSAGE_TIME"); + public final static Property IsRead = new Property(6, String.class, "isRead", false, "IS_READ"); + } + + + public LocaleMessageBeanDao(DaoConfig config) { + super(config); + } + + public LocaleMessageBeanDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(Database db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "\"LOCALE_MESSAGE_BEAN\" (" + // + "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "\"MESSAGE_ID\" TEXT UNIQUE ," + // 1: messageId + "\"USER_ID\" TEXT," + // 2: userId + "\"TITLE\" TEXT," + // 3: title + "\"CONTENT\" TEXT," + // 4: content + "\"MESSAGE_TIME\" TEXT," + // 5: messageTime + "\"IS_READ\" TEXT);"); // 6: isRead + } + + /** Drops the underlying database table. */ + public static void dropTable(Database db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"LOCALE_MESSAGE_BEAN\""; + db.execSQL(sql); + } + + @Override + protected final void bindValues(DatabaseStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + protected final void bindValues(SQLiteStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + @Override + public LocaleMessageBean readEntity(Cursor cursor, int offset) { + LocaleMessageBean entity = new LocaleMessageBean( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // messageId + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // userId + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // title + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // content + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // messageTime + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6) // isRead + ); + return entity; + } + + @Override + public void readEntity(Cursor cursor, LocaleMessageBean entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setMessageId(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); + entity.setUserId(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); + entity.setTitle(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); + entity.setContent(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); + entity.setMessageTime(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); + entity.setIsRead(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); + } + + @Override + protected final Long updateKeyAfterInsert(LocaleMessageBean entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + @Override + public Long getKey(LocaleMessageBean entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + @Override + public boolean hasKey(LocaleMessageBean entity) { + return entity.getId() != null; + } + + @Override + protected final boolean isEntityUpdateable() { + return true; + } + +} diff --git a/app/src/main/java/com/casic/br/model/LocaleMessageBean.java b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java new file mode 100644 index 0000000..1341da6 --- /dev/null +++ b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java @@ -0,0 +1,92 @@ +package com.casic.br.model; + +import org.greenrobot.greendao.annotation.Entity; +import org.greenrobot.greendao.annotation.Generated; +import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.Unique; + +@Entity +public class LocaleMessageBean { + @Id(autoincrement = true) + private Long id;//主键自增 + + @Unique + private String messageId; + private String userId; + private String title; + private String content; + private String messageTime; + private String isRead;//0-未读,1-已读 + + @Generated(hash = 22572871) + public LocaleMessageBean(Long id, String messageId, String userId, String title, + String content, String messageTime, String isRead) { + this.id = id; + this.messageId = messageId; + this.userId = userId; + this.title = title; + this.content = content; + this.messageTime = messageTime; + this.isRead = isRead; + } + + @Generated(hash = 1114477439) + public LocaleMessageBean() { + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMessageId() { + return this.messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getUserId() { + return this.userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMessageTime() { + return this.messageTime; + } + + public void setMessageTime(String messageTime) { + this.messageTime = messageTime; + } + + public String getIsRead() { + return this.isRead; + } + + public void setIsRead(String isRead) { + this.isRead = isRead; + } +} diff --git a/app/src/main/java/com/casic/br/utils/BadeHelper.kt b/app/src/main/java/com/casic/br/utils/BadeHelper.kt new file mode 100644 index 0000000..2db01eb --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/BadeHelper.kt @@ -0,0 +1,14 @@ +package com.casic.br.utils + +import android.content.Context +import me.leolin.shortcutbadger.ShortcutBadger + +object BadeHelper { + fun setBadgeNum(context: Context, badgeCount: Int) { + if (badgeCount == 0) { + ShortcutBadger.removeCount(context) + } else { + ShortcutBadger.applyCount(context, badgeCount) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/DataBaseManager.kt b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt new file mode 100644 index 0000000..3918b77 --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt @@ -0,0 +1,69 @@ +package com.casic.br.utils + +import com.casic.br.base.BaseApplication +import com.casic.br.greendao.LocaleMessageBeanDao +import com.casic.br.model.LocaleMessageBean + +class DataBaseManager private constructor() { + + companion object { + //Kotlin委托模式双重锁单例 + val instance: DataBaseManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + DataBaseManager() + } + } + + private val beanDao = BaseApplication.obtainInstance().obtainDaoSession().localeMessageBeanDao + + fun insertLocaleMessage( + messageId: String, userId: String, title: String, + content: String, isRead: String, messageTime: String + ) { + val messageBean = LocaleMessageBean() + messageBean.messageId = messageId + messageBean.userId = userId + messageBean.title = title + messageBean.content = content + messageBean.isRead = isRead + messageBean.messageTime = messageTime + beanDao.insert(messageBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun deleteLocaleMessageById(userId: String, messageId: String) { + val result = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).list() + beanDao.deleteInTx(result) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun updateLocaleMessageById(userId: String, messageId: String) { + val noticeLocaleBean = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).unique() ?: return + noticeLocaleBean.isRead = "1" + beanDao.update(noticeLocaleBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + + fun queryMessageByPage(userId: String, offset: Int): MutableList { + return BaseApplication.obtainInstance().obtainDaoSession() + .queryBuilder(LocaleMessageBean::class.java) + .where(LocaleMessageBeanDao.Properties.UserId.eq(userId)) + .offset(offset * LocaleConstant.PAGE_LIMIT) + .orderDesc(LocaleMessageBeanDao.Properties.MessageTime) + .limit(LocaleConstant.PAGE_LIMIT) + .list() + } + + private fun queryUnReadMessage(): Int { + return beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.IsRead.eq("0") + ).list().size + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt index 737e859..3b8dc98 100644 --- a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt @@ -35,6 +35,7 @@ * ============================================================================================= * */ const val PERMISSIONS_CODE = 999 + const val PAGE_LIMIT = 20 /** * ============================================================================================= diff --git a/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml new file mode 100644 index 0000000..f00d59c --- /dev/null +++ b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/DaoSession.java b/app/src/main/java/com/casic/br/greendao/DaoSession.java new file mode 100644 index 0000000..18d2242 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoSession.java @@ -0,0 +1,48 @@ +package com.casic.br.greendao; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.casic.br.model.LocaleMessageBean; + +import com.casic.br.greendao.LocaleMessageBeanDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig localeMessageBeanDaoConfig; + + private final LocaleMessageBeanDao localeMessageBeanDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + localeMessageBeanDaoConfig = daoConfigMap.get(LocaleMessageBeanDao.class).clone(); + localeMessageBeanDaoConfig.initIdentityScope(type); + + localeMessageBeanDao = new LocaleMessageBeanDao(localeMessageBeanDaoConfig, this); + + registerDao(LocaleMessageBean.class, localeMessageBeanDao); + } + + public void clear() { + localeMessageBeanDaoConfig.clearIdentityScope(); + } + + public LocaleMessageBeanDao getLocaleMessageBeanDao() { + return localeMessageBeanDao; + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java new file mode 100644 index 0000000..f41353a --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java @@ -0,0 +1,199 @@ +package com.casic.br.greendao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.Property; +import org.greenrobot.greendao.internal.DaoConfig; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseStatement; + +import com.casic.br.model.LocaleMessageBean; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table "LOCALE_MESSAGE_BEAN". +*/ +public class LocaleMessageBeanDao extends AbstractDao { + + public static final String TABLENAME = "LOCALE_MESSAGE_BEAN"; + + /** + * Properties of entity LocaleMessageBean.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property MessageId = new Property(1, String.class, "messageId", false, "MESSAGE_ID"); + public final static Property UserId = new Property(2, String.class, "userId", false, "USER_ID"); + public final static Property Title = new Property(3, String.class, "title", false, "TITLE"); + public final static Property Content = new Property(4, String.class, "content", false, "CONTENT"); + public final static Property MessageTime = new Property(5, String.class, "messageTime", false, "MESSAGE_TIME"); + public final static Property IsRead = new Property(6, String.class, "isRead", false, "IS_READ"); + } + + + public LocaleMessageBeanDao(DaoConfig config) { + super(config); + } + + public LocaleMessageBeanDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(Database db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "\"LOCALE_MESSAGE_BEAN\" (" + // + "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "\"MESSAGE_ID\" TEXT UNIQUE ," + // 1: messageId + "\"USER_ID\" TEXT," + // 2: userId + "\"TITLE\" TEXT," + // 3: title + "\"CONTENT\" TEXT," + // 4: content + "\"MESSAGE_TIME\" TEXT," + // 5: messageTime + "\"IS_READ\" TEXT);"); // 6: isRead + } + + /** Drops the underlying database table. */ + public static void dropTable(Database db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"LOCALE_MESSAGE_BEAN\""; + db.execSQL(sql); + } + + @Override + protected final void bindValues(DatabaseStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + protected final void bindValues(SQLiteStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + @Override + public LocaleMessageBean readEntity(Cursor cursor, int offset) { + LocaleMessageBean entity = new LocaleMessageBean( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // messageId + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // userId + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // title + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // content + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // messageTime + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6) // isRead + ); + return entity; + } + + @Override + public void readEntity(Cursor cursor, LocaleMessageBean entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setMessageId(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); + entity.setUserId(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); + entity.setTitle(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); + entity.setContent(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); + entity.setMessageTime(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); + entity.setIsRead(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); + } + + @Override + protected final Long updateKeyAfterInsert(LocaleMessageBean entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + @Override + public Long getKey(LocaleMessageBean entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + @Override + public boolean hasKey(LocaleMessageBean entity) { + return entity.getId() != null; + } + + @Override + protected final boolean isEntityUpdateable() { + return true; + } + +} diff --git a/app/src/main/java/com/casic/br/model/LocaleMessageBean.java b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java new file mode 100644 index 0000000..1341da6 --- /dev/null +++ b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java @@ -0,0 +1,92 @@ +package com.casic.br.model; + +import org.greenrobot.greendao.annotation.Entity; +import org.greenrobot.greendao.annotation.Generated; +import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.Unique; + +@Entity +public class LocaleMessageBean { + @Id(autoincrement = true) + private Long id;//主键自增 + + @Unique + private String messageId; + private String userId; + private String title; + private String content; + private String messageTime; + private String isRead;//0-未读,1-已读 + + @Generated(hash = 22572871) + public LocaleMessageBean(Long id, String messageId, String userId, String title, + String content, String messageTime, String isRead) { + this.id = id; + this.messageId = messageId; + this.userId = userId; + this.title = title; + this.content = content; + this.messageTime = messageTime; + this.isRead = isRead; + } + + @Generated(hash = 1114477439) + public LocaleMessageBean() { + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMessageId() { + return this.messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getUserId() { + return this.userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMessageTime() { + return this.messageTime; + } + + public void setMessageTime(String messageTime) { + this.messageTime = messageTime; + } + + public String getIsRead() { + return this.isRead; + } + + public void setIsRead(String isRead) { + this.isRead = isRead; + } +} diff --git a/app/src/main/java/com/casic/br/utils/BadeHelper.kt b/app/src/main/java/com/casic/br/utils/BadeHelper.kt new file mode 100644 index 0000000..2db01eb --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/BadeHelper.kt @@ -0,0 +1,14 @@ +package com.casic.br.utils + +import android.content.Context +import me.leolin.shortcutbadger.ShortcutBadger + +object BadeHelper { + fun setBadgeNum(context: Context, badgeCount: Int) { + if (badgeCount == 0) { + ShortcutBadger.removeCount(context) + } else { + ShortcutBadger.applyCount(context, badgeCount) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/DataBaseManager.kt b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt new file mode 100644 index 0000000..3918b77 --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt @@ -0,0 +1,69 @@ +package com.casic.br.utils + +import com.casic.br.base.BaseApplication +import com.casic.br.greendao.LocaleMessageBeanDao +import com.casic.br.model.LocaleMessageBean + +class DataBaseManager private constructor() { + + companion object { + //Kotlin委托模式双重锁单例 + val instance: DataBaseManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + DataBaseManager() + } + } + + private val beanDao = BaseApplication.obtainInstance().obtainDaoSession().localeMessageBeanDao + + fun insertLocaleMessage( + messageId: String, userId: String, title: String, + content: String, isRead: String, messageTime: String + ) { + val messageBean = LocaleMessageBean() + messageBean.messageId = messageId + messageBean.userId = userId + messageBean.title = title + messageBean.content = content + messageBean.isRead = isRead + messageBean.messageTime = messageTime + beanDao.insert(messageBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun deleteLocaleMessageById(userId: String, messageId: String) { + val result = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).list() + beanDao.deleteInTx(result) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun updateLocaleMessageById(userId: String, messageId: String) { + val noticeLocaleBean = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).unique() ?: return + noticeLocaleBean.isRead = "1" + beanDao.update(noticeLocaleBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + + fun queryMessageByPage(userId: String, offset: Int): MutableList { + return BaseApplication.obtainInstance().obtainDaoSession() + .queryBuilder(LocaleMessageBean::class.java) + .where(LocaleMessageBeanDao.Properties.UserId.eq(userId)) + .offset(offset * LocaleConstant.PAGE_LIMIT) + .orderDesc(LocaleMessageBeanDao.Properties.MessageTime) + .limit(LocaleConstant.PAGE_LIMIT) + .list() + } + + private fun queryUnReadMessage(): Int { + return beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.IsRead.eq("0") + ).list().size + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt index 737e859..3b8dc98 100644 --- a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt @@ -35,6 +35,7 @@ * ============================================================================================= * */ const val PERMISSIONS_CODE = 999 + const val PAGE_LIMIT = 20 /** * ============================================================================================= diff --git a/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml new file mode 100644 index 0000000..f00d59c --- /dev/null +++ b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dash_line_gray.xml b/app/src/main/res/drawable/dash_line_gray.xml new file mode 100644 index 0000000..61ca4c0 --- /dev/null +++ b/app/src/main/res/drawable/dash_line_gray.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/DaoSession.java b/app/src/main/java/com/casic/br/greendao/DaoSession.java new file mode 100644 index 0000000..18d2242 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoSession.java @@ -0,0 +1,48 @@ +package com.casic.br.greendao; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.casic.br.model.LocaleMessageBean; + +import com.casic.br.greendao.LocaleMessageBeanDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig localeMessageBeanDaoConfig; + + private final LocaleMessageBeanDao localeMessageBeanDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + localeMessageBeanDaoConfig = daoConfigMap.get(LocaleMessageBeanDao.class).clone(); + localeMessageBeanDaoConfig.initIdentityScope(type); + + localeMessageBeanDao = new LocaleMessageBeanDao(localeMessageBeanDaoConfig, this); + + registerDao(LocaleMessageBean.class, localeMessageBeanDao); + } + + public void clear() { + localeMessageBeanDaoConfig.clearIdentityScope(); + } + + public LocaleMessageBeanDao getLocaleMessageBeanDao() { + return localeMessageBeanDao; + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java new file mode 100644 index 0000000..f41353a --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java @@ -0,0 +1,199 @@ +package com.casic.br.greendao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.Property; +import org.greenrobot.greendao.internal.DaoConfig; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseStatement; + +import com.casic.br.model.LocaleMessageBean; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table "LOCALE_MESSAGE_BEAN". +*/ +public class LocaleMessageBeanDao extends AbstractDao { + + public static final String TABLENAME = "LOCALE_MESSAGE_BEAN"; + + /** + * Properties of entity LocaleMessageBean.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property MessageId = new Property(1, String.class, "messageId", false, "MESSAGE_ID"); + public final static Property UserId = new Property(2, String.class, "userId", false, "USER_ID"); + public final static Property Title = new Property(3, String.class, "title", false, "TITLE"); + public final static Property Content = new Property(4, String.class, "content", false, "CONTENT"); + public final static Property MessageTime = new Property(5, String.class, "messageTime", false, "MESSAGE_TIME"); + public final static Property IsRead = new Property(6, String.class, "isRead", false, "IS_READ"); + } + + + public LocaleMessageBeanDao(DaoConfig config) { + super(config); + } + + public LocaleMessageBeanDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(Database db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "\"LOCALE_MESSAGE_BEAN\" (" + // + "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "\"MESSAGE_ID\" TEXT UNIQUE ," + // 1: messageId + "\"USER_ID\" TEXT," + // 2: userId + "\"TITLE\" TEXT," + // 3: title + "\"CONTENT\" TEXT," + // 4: content + "\"MESSAGE_TIME\" TEXT," + // 5: messageTime + "\"IS_READ\" TEXT);"); // 6: isRead + } + + /** Drops the underlying database table. */ + public static void dropTable(Database db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"LOCALE_MESSAGE_BEAN\""; + db.execSQL(sql); + } + + @Override + protected final void bindValues(DatabaseStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + protected final void bindValues(SQLiteStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + @Override + public LocaleMessageBean readEntity(Cursor cursor, int offset) { + LocaleMessageBean entity = new LocaleMessageBean( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // messageId + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // userId + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // title + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // content + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // messageTime + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6) // isRead + ); + return entity; + } + + @Override + public void readEntity(Cursor cursor, LocaleMessageBean entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setMessageId(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); + entity.setUserId(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); + entity.setTitle(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); + entity.setContent(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); + entity.setMessageTime(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); + entity.setIsRead(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); + } + + @Override + protected final Long updateKeyAfterInsert(LocaleMessageBean entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + @Override + public Long getKey(LocaleMessageBean entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + @Override + public boolean hasKey(LocaleMessageBean entity) { + return entity.getId() != null; + } + + @Override + protected final boolean isEntityUpdateable() { + return true; + } + +} diff --git a/app/src/main/java/com/casic/br/model/LocaleMessageBean.java b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java new file mode 100644 index 0000000..1341da6 --- /dev/null +++ b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java @@ -0,0 +1,92 @@ +package com.casic.br.model; + +import org.greenrobot.greendao.annotation.Entity; +import org.greenrobot.greendao.annotation.Generated; +import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.Unique; + +@Entity +public class LocaleMessageBean { + @Id(autoincrement = true) + private Long id;//主键自增 + + @Unique + private String messageId; + private String userId; + private String title; + private String content; + private String messageTime; + private String isRead;//0-未读,1-已读 + + @Generated(hash = 22572871) + public LocaleMessageBean(Long id, String messageId, String userId, String title, + String content, String messageTime, String isRead) { + this.id = id; + this.messageId = messageId; + this.userId = userId; + this.title = title; + this.content = content; + this.messageTime = messageTime; + this.isRead = isRead; + } + + @Generated(hash = 1114477439) + public LocaleMessageBean() { + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMessageId() { + return this.messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getUserId() { + return this.userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMessageTime() { + return this.messageTime; + } + + public void setMessageTime(String messageTime) { + this.messageTime = messageTime; + } + + public String getIsRead() { + return this.isRead; + } + + public void setIsRead(String isRead) { + this.isRead = isRead; + } +} diff --git a/app/src/main/java/com/casic/br/utils/BadeHelper.kt b/app/src/main/java/com/casic/br/utils/BadeHelper.kt new file mode 100644 index 0000000..2db01eb --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/BadeHelper.kt @@ -0,0 +1,14 @@ +package com.casic.br.utils + +import android.content.Context +import me.leolin.shortcutbadger.ShortcutBadger + +object BadeHelper { + fun setBadgeNum(context: Context, badgeCount: Int) { + if (badgeCount == 0) { + ShortcutBadger.removeCount(context) + } else { + ShortcutBadger.applyCount(context, badgeCount) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/DataBaseManager.kt b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt new file mode 100644 index 0000000..3918b77 --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt @@ -0,0 +1,69 @@ +package com.casic.br.utils + +import com.casic.br.base.BaseApplication +import com.casic.br.greendao.LocaleMessageBeanDao +import com.casic.br.model.LocaleMessageBean + +class DataBaseManager private constructor() { + + companion object { + //Kotlin委托模式双重锁单例 + val instance: DataBaseManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + DataBaseManager() + } + } + + private val beanDao = BaseApplication.obtainInstance().obtainDaoSession().localeMessageBeanDao + + fun insertLocaleMessage( + messageId: String, userId: String, title: String, + content: String, isRead: String, messageTime: String + ) { + val messageBean = LocaleMessageBean() + messageBean.messageId = messageId + messageBean.userId = userId + messageBean.title = title + messageBean.content = content + messageBean.isRead = isRead + messageBean.messageTime = messageTime + beanDao.insert(messageBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun deleteLocaleMessageById(userId: String, messageId: String) { + val result = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).list() + beanDao.deleteInTx(result) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun updateLocaleMessageById(userId: String, messageId: String) { + val noticeLocaleBean = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).unique() ?: return + noticeLocaleBean.isRead = "1" + beanDao.update(noticeLocaleBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + + fun queryMessageByPage(userId: String, offset: Int): MutableList { + return BaseApplication.obtainInstance().obtainDaoSession() + .queryBuilder(LocaleMessageBean::class.java) + .where(LocaleMessageBeanDao.Properties.UserId.eq(userId)) + .offset(offset * LocaleConstant.PAGE_LIMIT) + .orderDesc(LocaleMessageBeanDao.Properties.MessageTime) + .limit(LocaleConstant.PAGE_LIMIT) + .list() + } + + private fun queryUnReadMessage(): Int { + return beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.IsRead.eq("0") + ).list().size + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt index 737e859..3b8dc98 100644 --- a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt @@ -35,6 +35,7 @@ * ============================================================================================= * */ const val PERMISSIONS_CODE = 999 + const val PAGE_LIMIT = 20 /** * ============================================================================================= diff --git a/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml new file mode 100644 index 0000000..f00d59c --- /dev/null +++ b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dash_line_gray.xml b/app/src/main/res/drawable/dash_line_gray.xml new file mode 100644 index 0000000..61ca4c0 --- /dev/null +++ b/app/src/main/res/drawable/dash_line_gray.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dot_red.xml b/app/src/main/res/drawable/dot_red.xml new file mode 100644 index 0000000..fa97466 --- /dev/null +++ b/app/src/main/res/drawable/dot_red.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/DaoSession.java b/app/src/main/java/com/casic/br/greendao/DaoSession.java new file mode 100644 index 0000000..18d2242 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoSession.java @@ -0,0 +1,48 @@ +package com.casic.br.greendao; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.casic.br.model.LocaleMessageBean; + +import com.casic.br.greendao.LocaleMessageBeanDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig localeMessageBeanDaoConfig; + + private final LocaleMessageBeanDao localeMessageBeanDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + localeMessageBeanDaoConfig = daoConfigMap.get(LocaleMessageBeanDao.class).clone(); + localeMessageBeanDaoConfig.initIdentityScope(type); + + localeMessageBeanDao = new LocaleMessageBeanDao(localeMessageBeanDaoConfig, this); + + registerDao(LocaleMessageBean.class, localeMessageBeanDao); + } + + public void clear() { + localeMessageBeanDaoConfig.clearIdentityScope(); + } + + public LocaleMessageBeanDao getLocaleMessageBeanDao() { + return localeMessageBeanDao; + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java new file mode 100644 index 0000000..f41353a --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java @@ -0,0 +1,199 @@ +package com.casic.br.greendao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.Property; +import org.greenrobot.greendao.internal.DaoConfig; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseStatement; + +import com.casic.br.model.LocaleMessageBean; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table "LOCALE_MESSAGE_BEAN". +*/ +public class LocaleMessageBeanDao extends AbstractDao { + + public static final String TABLENAME = "LOCALE_MESSAGE_BEAN"; + + /** + * Properties of entity LocaleMessageBean.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property MessageId = new Property(1, String.class, "messageId", false, "MESSAGE_ID"); + public final static Property UserId = new Property(2, String.class, "userId", false, "USER_ID"); + public final static Property Title = new Property(3, String.class, "title", false, "TITLE"); + public final static Property Content = new Property(4, String.class, "content", false, "CONTENT"); + public final static Property MessageTime = new Property(5, String.class, "messageTime", false, "MESSAGE_TIME"); + public final static Property IsRead = new Property(6, String.class, "isRead", false, "IS_READ"); + } + + + public LocaleMessageBeanDao(DaoConfig config) { + super(config); + } + + public LocaleMessageBeanDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(Database db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "\"LOCALE_MESSAGE_BEAN\" (" + // + "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "\"MESSAGE_ID\" TEXT UNIQUE ," + // 1: messageId + "\"USER_ID\" TEXT," + // 2: userId + "\"TITLE\" TEXT," + // 3: title + "\"CONTENT\" TEXT," + // 4: content + "\"MESSAGE_TIME\" TEXT," + // 5: messageTime + "\"IS_READ\" TEXT);"); // 6: isRead + } + + /** Drops the underlying database table. */ + public static void dropTable(Database db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"LOCALE_MESSAGE_BEAN\""; + db.execSQL(sql); + } + + @Override + protected final void bindValues(DatabaseStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + protected final void bindValues(SQLiteStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + @Override + public LocaleMessageBean readEntity(Cursor cursor, int offset) { + LocaleMessageBean entity = new LocaleMessageBean( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // messageId + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // userId + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // title + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // content + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // messageTime + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6) // isRead + ); + return entity; + } + + @Override + public void readEntity(Cursor cursor, LocaleMessageBean entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setMessageId(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); + entity.setUserId(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); + entity.setTitle(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); + entity.setContent(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); + entity.setMessageTime(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); + entity.setIsRead(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); + } + + @Override + protected final Long updateKeyAfterInsert(LocaleMessageBean entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + @Override + public Long getKey(LocaleMessageBean entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + @Override + public boolean hasKey(LocaleMessageBean entity) { + return entity.getId() != null; + } + + @Override + protected final boolean isEntityUpdateable() { + return true; + } + +} diff --git a/app/src/main/java/com/casic/br/model/LocaleMessageBean.java b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java new file mode 100644 index 0000000..1341da6 --- /dev/null +++ b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java @@ -0,0 +1,92 @@ +package com.casic.br.model; + +import org.greenrobot.greendao.annotation.Entity; +import org.greenrobot.greendao.annotation.Generated; +import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.Unique; + +@Entity +public class LocaleMessageBean { + @Id(autoincrement = true) + private Long id;//主键自增 + + @Unique + private String messageId; + private String userId; + private String title; + private String content; + private String messageTime; + private String isRead;//0-未读,1-已读 + + @Generated(hash = 22572871) + public LocaleMessageBean(Long id, String messageId, String userId, String title, + String content, String messageTime, String isRead) { + this.id = id; + this.messageId = messageId; + this.userId = userId; + this.title = title; + this.content = content; + this.messageTime = messageTime; + this.isRead = isRead; + } + + @Generated(hash = 1114477439) + public LocaleMessageBean() { + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMessageId() { + return this.messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getUserId() { + return this.userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMessageTime() { + return this.messageTime; + } + + public void setMessageTime(String messageTime) { + this.messageTime = messageTime; + } + + public String getIsRead() { + return this.isRead; + } + + public void setIsRead(String isRead) { + this.isRead = isRead; + } +} diff --git a/app/src/main/java/com/casic/br/utils/BadeHelper.kt b/app/src/main/java/com/casic/br/utils/BadeHelper.kt new file mode 100644 index 0000000..2db01eb --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/BadeHelper.kt @@ -0,0 +1,14 @@ +package com.casic.br.utils + +import android.content.Context +import me.leolin.shortcutbadger.ShortcutBadger + +object BadeHelper { + fun setBadgeNum(context: Context, badgeCount: Int) { + if (badgeCount == 0) { + ShortcutBadger.removeCount(context) + } else { + ShortcutBadger.applyCount(context, badgeCount) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/DataBaseManager.kt b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt new file mode 100644 index 0000000..3918b77 --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt @@ -0,0 +1,69 @@ +package com.casic.br.utils + +import com.casic.br.base.BaseApplication +import com.casic.br.greendao.LocaleMessageBeanDao +import com.casic.br.model.LocaleMessageBean + +class DataBaseManager private constructor() { + + companion object { + //Kotlin委托模式双重锁单例 + val instance: DataBaseManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + DataBaseManager() + } + } + + private val beanDao = BaseApplication.obtainInstance().obtainDaoSession().localeMessageBeanDao + + fun insertLocaleMessage( + messageId: String, userId: String, title: String, + content: String, isRead: String, messageTime: String + ) { + val messageBean = LocaleMessageBean() + messageBean.messageId = messageId + messageBean.userId = userId + messageBean.title = title + messageBean.content = content + messageBean.isRead = isRead + messageBean.messageTime = messageTime + beanDao.insert(messageBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun deleteLocaleMessageById(userId: String, messageId: String) { + val result = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).list() + beanDao.deleteInTx(result) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun updateLocaleMessageById(userId: String, messageId: String) { + val noticeLocaleBean = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).unique() ?: return + noticeLocaleBean.isRead = "1" + beanDao.update(noticeLocaleBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + + fun queryMessageByPage(userId: String, offset: Int): MutableList { + return BaseApplication.obtainInstance().obtainDaoSession() + .queryBuilder(LocaleMessageBean::class.java) + .where(LocaleMessageBeanDao.Properties.UserId.eq(userId)) + .offset(offset * LocaleConstant.PAGE_LIMIT) + .orderDesc(LocaleMessageBeanDao.Properties.MessageTime) + .limit(LocaleConstant.PAGE_LIMIT) + .list() + } + + private fun queryUnReadMessage(): Int { + return beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.IsRead.eq("0") + ).list().size + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt index 737e859..3b8dc98 100644 --- a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt @@ -35,6 +35,7 @@ * ============================================================================================= * */ const val PERMISSIONS_CODE = 999 + const val PAGE_LIMIT = 20 /** * ============================================================================================= diff --git a/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml new file mode 100644 index 0000000..f00d59c --- /dev/null +++ b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dash_line_gray.xml b/app/src/main/res/drawable/dash_line_gray.xml new file mode 100644 index 0000000..61ca4c0 --- /dev/null +++ b/app/src/main/res/drawable/dash_line_gray.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dot_red.xml b/app/src/main/res/drawable/dot_red.xml new file mode 100644 index 0000000..fa97466 --- /dev/null +++ b/app/src/main/res/drawable/dot_red.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml new file mode 100644 index 0000000..ef661b6 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/DaoSession.java b/app/src/main/java/com/casic/br/greendao/DaoSession.java new file mode 100644 index 0000000..18d2242 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoSession.java @@ -0,0 +1,48 @@ +package com.casic.br.greendao; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.casic.br.model.LocaleMessageBean; + +import com.casic.br.greendao.LocaleMessageBeanDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig localeMessageBeanDaoConfig; + + private final LocaleMessageBeanDao localeMessageBeanDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + localeMessageBeanDaoConfig = daoConfigMap.get(LocaleMessageBeanDao.class).clone(); + localeMessageBeanDaoConfig.initIdentityScope(type); + + localeMessageBeanDao = new LocaleMessageBeanDao(localeMessageBeanDaoConfig, this); + + registerDao(LocaleMessageBean.class, localeMessageBeanDao); + } + + public void clear() { + localeMessageBeanDaoConfig.clearIdentityScope(); + } + + public LocaleMessageBeanDao getLocaleMessageBeanDao() { + return localeMessageBeanDao; + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java new file mode 100644 index 0000000..f41353a --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java @@ -0,0 +1,199 @@ +package com.casic.br.greendao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.Property; +import org.greenrobot.greendao.internal.DaoConfig; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseStatement; + +import com.casic.br.model.LocaleMessageBean; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table "LOCALE_MESSAGE_BEAN". +*/ +public class LocaleMessageBeanDao extends AbstractDao { + + public static final String TABLENAME = "LOCALE_MESSAGE_BEAN"; + + /** + * Properties of entity LocaleMessageBean.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property MessageId = new Property(1, String.class, "messageId", false, "MESSAGE_ID"); + public final static Property UserId = new Property(2, String.class, "userId", false, "USER_ID"); + public final static Property Title = new Property(3, String.class, "title", false, "TITLE"); + public final static Property Content = new Property(4, String.class, "content", false, "CONTENT"); + public final static Property MessageTime = new Property(5, String.class, "messageTime", false, "MESSAGE_TIME"); + public final static Property IsRead = new Property(6, String.class, "isRead", false, "IS_READ"); + } + + + public LocaleMessageBeanDao(DaoConfig config) { + super(config); + } + + public LocaleMessageBeanDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(Database db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "\"LOCALE_MESSAGE_BEAN\" (" + // + "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "\"MESSAGE_ID\" TEXT UNIQUE ," + // 1: messageId + "\"USER_ID\" TEXT," + // 2: userId + "\"TITLE\" TEXT," + // 3: title + "\"CONTENT\" TEXT," + // 4: content + "\"MESSAGE_TIME\" TEXT," + // 5: messageTime + "\"IS_READ\" TEXT);"); // 6: isRead + } + + /** Drops the underlying database table. */ + public static void dropTable(Database db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"LOCALE_MESSAGE_BEAN\""; + db.execSQL(sql); + } + + @Override + protected final void bindValues(DatabaseStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + protected final void bindValues(SQLiteStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + @Override + public LocaleMessageBean readEntity(Cursor cursor, int offset) { + LocaleMessageBean entity = new LocaleMessageBean( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // messageId + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // userId + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // title + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // content + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // messageTime + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6) // isRead + ); + return entity; + } + + @Override + public void readEntity(Cursor cursor, LocaleMessageBean entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setMessageId(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); + entity.setUserId(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); + entity.setTitle(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); + entity.setContent(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); + entity.setMessageTime(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); + entity.setIsRead(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); + } + + @Override + protected final Long updateKeyAfterInsert(LocaleMessageBean entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + @Override + public Long getKey(LocaleMessageBean entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + @Override + public boolean hasKey(LocaleMessageBean entity) { + return entity.getId() != null; + } + + @Override + protected final boolean isEntityUpdateable() { + return true; + } + +} diff --git a/app/src/main/java/com/casic/br/model/LocaleMessageBean.java b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java new file mode 100644 index 0000000..1341da6 --- /dev/null +++ b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java @@ -0,0 +1,92 @@ +package com.casic.br.model; + +import org.greenrobot.greendao.annotation.Entity; +import org.greenrobot.greendao.annotation.Generated; +import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.Unique; + +@Entity +public class LocaleMessageBean { + @Id(autoincrement = true) + private Long id;//主键自增 + + @Unique + private String messageId; + private String userId; + private String title; + private String content; + private String messageTime; + private String isRead;//0-未读,1-已读 + + @Generated(hash = 22572871) + public LocaleMessageBean(Long id, String messageId, String userId, String title, + String content, String messageTime, String isRead) { + this.id = id; + this.messageId = messageId; + this.userId = userId; + this.title = title; + this.content = content; + this.messageTime = messageTime; + this.isRead = isRead; + } + + @Generated(hash = 1114477439) + public LocaleMessageBean() { + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMessageId() { + return this.messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getUserId() { + return this.userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMessageTime() { + return this.messageTime; + } + + public void setMessageTime(String messageTime) { + this.messageTime = messageTime; + } + + public String getIsRead() { + return this.isRead; + } + + public void setIsRead(String isRead) { + this.isRead = isRead; + } +} diff --git a/app/src/main/java/com/casic/br/utils/BadeHelper.kt b/app/src/main/java/com/casic/br/utils/BadeHelper.kt new file mode 100644 index 0000000..2db01eb --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/BadeHelper.kt @@ -0,0 +1,14 @@ +package com.casic.br.utils + +import android.content.Context +import me.leolin.shortcutbadger.ShortcutBadger + +object BadeHelper { + fun setBadgeNum(context: Context, badgeCount: Int) { + if (badgeCount == 0) { + ShortcutBadger.removeCount(context) + } else { + ShortcutBadger.applyCount(context, badgeCount) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/DataBaseManager.kt b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt new file mode 100644 index 0000000..3918b77 --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt @@ -0,0 +1,69 @@ +package com.casic.br.utils + +import com.casic.br.base.BaseApplication +import com.casic.br.greendao.LocaleMessageBeanDao +import com.casic.br.model.LocaleMessageBean + +class DataBaseManager private constructor() { + + companion object { + //Kotlin委托模式双重锁单例 + val instance: DataBaseManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + DataBaseManager() + } + } + + private val beanDao = BaseApplication.obtainInstance().obtainDaoSession().localeMessageBeanDao + + fun insertLocaleMessage( + messageId: String, userId: String, title: String, + content: String, isRead: String, messageTime: String + ) { + val messageBean = LocaleMessageBean() + messageBean.messageId = messageId + messageBean.userId = userId + messageBean.title = title + messageBean.content = content + messageBean.isRead = isRead + messageBean.messageTime = messageTime + beanDao.insert(messageBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun deleteLocaleMessageById(userId: String, messageId: String) { + val result = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).list() + beanDao.deleteInTx(result) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun updateLocaleMessageById(userId: String, messageId: String) { + val noticeLocaleBean = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).unique() ?: return + noticeLocaleBean.isRead = "1" + beanDao.update(noticeLocaleBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + + fun queryMessageByPage(userId: String, offset: Int): MutableList { + return BaseApplication.obtainInstance().obtainDaoSession() + .queryBuilder(LocaleMessageBean::class.java) + .where(LocaleMessageBeanDao.Properties.UserId.eq(userId)) + .offset(offset * LocaleConstant.PAGE_LIMIT) + .orderDesc(LocaleMessageBeanDao.Properties.MessageTime) + .limit(LocaleConstant.PAGE_LIMIT) + .list() + } + + private fun queryUnReadMessage(): Int { + return beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.IsRead.eq("0") + ).list().size + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt index 737e859..3b8dc98 100644 --- a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt @@ -35,6 +35,7 @@ * ============================================================================================= * */ const val PERMISSIONS_CODE = 999 + const val PAGE_LIMIT = 20 /** * ============================================================================================= diff --git a/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml new file mode 100644 index 0000000..f00d59c --- /dev/null +++ b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dash_line_gray.xml b/app/src/main/res/drawable/dash_line_gray.xml new file mode 100644 index 0000000..61ca4c0 --- /dev/null +++ b/app/src/main/res/drawable/dash_line_gray.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dot_red.xml b/app/src/main/res/drawable/dot_red.xml new file mode 100644 index 0000000..fa97466 --- /dev/null +++ b/app/src/main/res/drawable/dot_red.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml new file mode 100644 index 0000000..ef661b6 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_message_tag.xml b/app/src/main/res/drawable/ic_message_tag.xml new file mode 100644 index 0000000..8650128 --- /dev/null +++ b/app/src/main/res/drawable/ic_message_tag.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/DaoSession.java b/app/src/main/java/com/casic/br/greendao/DaoSession.java new file mode 100644 index 0000000..18d2242 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoSession.java @@ -0,0 +1,48 @@ +package com.casic.br.greendao; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.casic.br.model.LocaleMessageBean; + +import com.casic.br.greendao.LocaleMessageBeanDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig localeMessageBeanDaoConfig; + + private final LocaleMessageBeanDao localeMessageBeanDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + localeMessageBeanDaoConfig = daoConfigMap.get(LocaleMessageBeanDao.class).clone(); + localeMessageBeanDaoConfig.initIdentityScope(type); + + localeMessageBeanDao = new LocaleMessageBeanDao(localeMessageBeanDaoConfig, this); + + registerDao(LocaleMessageBean.class, localeMessageBeanDao); + } + + public void clear() { + localeMessageBeanDaoConfig.clearIdentityScope(); + } + + public LocaleMessageBeanDao getLocaleMessageBeanDao() { + return localeMessageBeanDao; + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java new file mode 100644 index 0000000..f41353a --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java @@ -0,0 +1,199 @@ +package com.casic.br.greendao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.Property; +import org.greenrobot.greendao.internal.DaoConfig; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseStatement; + +import com.casic.br.model.LocaleMessageBean; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table "LOCALE_MESSAGE_BEAN". +*/ +public class LocaleMessageBeanDao extends AbstractDao { + + public static final String TABLENAME = "LOCALE_MESSAGE_BEAN"; + + /** + * Properties of entity LocaleMessageBean.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property MessageId = new Property(1, String.class, "messageId", false, "MESSAGE_ID"); + public final static Property UserId = new Property(2, String.class, "userId", false, "USER_ID"); + public final static Property Title = new Property(3, String.class, "title", false, "TITLE"); + public final static Property Content = new Property(4, String.class, "content", false, "CONTENT"); + public final static Property MessageTime = new Property(5, String.class, "messageTime", false, "MESSAGE_TIME"); + public final static Property IsRead = new Property(6, String.class, "isRead", false, "IS_READ"); + } + + + public LocaleMessageBeanDao(DaoConfig config) { + super(config); + } + + public LocaleMessageBeanDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(Database db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "\"LOCALE_MESSAGE_BEAN\" (" + // + "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "\"MESSAGE_ID\" TEXT UNIQUE ," + // 1: messageId + "\"USER_ID\" TEXT," + // 2: userId + "\"TITLE\" TEXT," + // 3: title + "\"CONTENT\" TEXT," + // 4: content + "\"MESSAGE_TIME\" TEXT," + // 5: messageTime + "\"IS_READ\" TEXT);"); // 6: isRead + } + + /** Drops the underlying database table. */ + public static void dropTable(Database db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"LOCALE_MESSAGE_BEAN\""; + db.execSQL(sql); + } + + @Override + protected final void bindValues(DatabaseStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + protected final void bindValues(SQLiteStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + @Override + public LocaleMessageBean readEntity(Cursor cursor, int offset) { + LocaleMessageBean entity = new LocaleMessageBean( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // messageId + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // userId + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // title + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // content + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // messageTime + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6) // isRead + ); + return entity; + } + + @Override + public void readEntity(Cursor cursor, LocaleMessageBean entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setMessageId(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); + entity.setUserId(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); + entity.setTitle(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); + entity.setContent(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); + entity.setMessageTime(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); + entity.setIsRead(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); + } + + @Override + protected final Long updateKeyAfterInsert(LocaleMessageBean entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + @Override + public Long getKey(LocaleMessageBean entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + @Override + public boolean hasKey(LocaleMessageBean entity) { + return entity.getId() != null; + } + + @Override + protected final boolean isEntityUpdateable() { + return true; + } + +} diff --git a/app/src/main/java/com/casic/br/model/LocaleMessageBean.java b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java new file mode 100644 index 0000000..1341da6 --- /dev/null +++ b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java @@ -0,0 +1,92 @@ +package com.casic.br.model; + +import org.greenrobot.greendao.annotation.Entity; +import org.greenrobot.greendao.annotation.Generated; +import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.Unique; + +@Entity +public class LocaleMessageBean { + @Id(autoincrement = true) + private Long id;//主键自增 + + @Unique + private String messageId; + private String userId; + private String title; + private String content; + private String messageTime; + private String isRead;//0-未读,1-已读 + + @Generated(hash = 22572871) + public LocaleMessageBean(Long id, String messageId, String userId, String title, + String content, String messageTime, String isRead) { + this.id = id; + this.messageId = messageId; + this.userId = userId; + this.title = title; + this.content = content; + this.messageTime = messageTime; + this.isRead = isRead; + } + + @Generated(hash = 1114477439) + public LocaleMessageBean() { + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMessageId() { + return this.messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getUserId() { + return this.userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMessageTime() { + return this.messageTime; + } + + public void setMessageTime(String messageTime) { + this.messageTime = messageTime; + } + + public String getIsRead() { + return this.isRead; + } + + public void setIsRead(String isRead) { + this.isRead = isRead; + } +} diff --git a/app/src/main/java/com/casic/br/utils/BadeHelper.kt b/app/src/main/java/com/casic/br/utils/BadeHelper.kt new file mode 100644 index 0000000..2db01eb --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/BadeHelper.kt @@ -0,0 +1,14 @@ +package com.casic.br.utils + +import android.content.Context +import me.leolin.shortcutbadger.ShortcutBadger + +object BadeHelper { + fun setBadgeNum(context: Context, badgeCount: Int) { + if (badgeCount == 0) { + ShortcutBadger.removeCount(context) + } else { + ShortcutBadger.applyCount(context, badgeCount) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/DataBaseManager.kt b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt new file mode 100644 index 0000000..3918b77 --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt @@ -0,0 +1,69 @@ +package com.casic.br.utils + +import com.casic.br.base.BaseApplication +import com.casic.br.greendao.LocaleMessageBeanDao +import com.casic.br.model.LocaleMessageBean + +class DataBaseManager private constructor() { + + companion object { + //Kotlin委托模式双重锁单例 + val instance: DataBaseManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + DataBaseManager() + } + } + + private val beanDao = BaseApplication.obtainInstance().obtainDaoSession().localeMessageBeanDao + + fun insertLocaleMessage( + messageId: String, userId: String, title: String, + content: String, isRead: String, messageTime: String + ) { + val messageBean = LocaleMessageBean() + messageBean.messageId = messageId + messageBean.userId = userId + messageBean.title = title + messageBean.content = content + messageBean.isRead = isRead + messageBean.messageTime = messageTime + beanDao.insert(messageBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun deleteLocaleMessageById(userId: String, messageId: String) { + val result = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).list() + beanDao.deleteInTx(result) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun updateLocaleMessageById(userId: String, messageId: String) { + val noticeLocaleBean = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).unique() ?: return + noticeLocaleBean.isRead = "1" + beanDao.update(noticeLocaleBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + + fun queryMessageByPage(userId: String, offset: Int): MutableList { + return BaseApplication.obtainInstance().obtainDaoSession() + .queryBuilder(LocaleMessageBean::class.java) + .where(LocaleMessageBeanDao.Properties.UserId.eq(userId)) + .offset(offset * LocaleConstant.PAGE_LIMIT) + .orderDesc(LocaleMessageBeanDao.Properties.MessageTime) + .limit(LocaleConstant.PAGE_LIMIT) + .list() + } + + private fun queryUnReadMessage(): Int { + return beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.IsRead.eq("0") + ).list().size + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt index 737e859..3b8dc98 100644 --- a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt @@ -35,6 +35,7 @@ * ============================================================================================= * */ const val PERMISSIONS_CODE = 999 + const val PAGE_LIMIT = 20 /** * ============================================================================================= diff --git a/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml new file mode 100644 index 0000000..f00d59c --- /dev/null +++ b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dash_line_gray.xml b/app/src/main/res/drawable/dash_line_gray.xml new file mode 100644 index 0000000..61ca4c0 --- /dev/null +++ b/app/src/main/res/drawable/dash_line_gray.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dot_red.xml b/app/src/main/res/drawable/dot_red.xml new file mode 100644 index 0000000..fa97466 --- /dev/null +++ b/app/src/main/res/drawable/dot_red.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml new file mode 100644 index 0000000..ef661b6 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_message_tag.xml b/app/src/main/res/drawable/ic_message_tag.xml new file mode 100644 index 0000000..8650128 --- /dev/null +++ b/app/src/main/res/drawable/ic_message_tag.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/layout/fragment_message.xml b/app/src/main/res/layout/fragment_message.xml index a97ec1b..9537d5b 100644 --- a/app/src/main/res/layout/fragment_message.xml +++ b/app/src/main/res/layout/fragment_message.xml @@ -1,5 +1,6 @@ + android:layout_marginTop="1dp" + android:background="@color/white" + android:orientation="vertical"> + + + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/DaoSession.java b/app/src/main/java/com/casic/br/greendao/DaoSession.java new file mode 100644 index 0000000..18d2242 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoSession.java @@ -0,0 +1,48 @@ +package com.casic.br.greendao; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.casic.br.model.LocaleMessageBean; + +import com.casic.br.greendao.LocaleMessageBeanDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig localeMessageBeanDaoConfig; + + private final LocaleMessageBeanDao localeMessageBeanDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + localeMessageBeanDaoConfig = daoConfigMap.get(LocaleMessageBeanDao.class).clone(); + localeMessageBeanDaoConfig.initIdentityScope(type); + + localeMessageBeanDao = new LocaleMessageBeanDao(localeMessageBeanDaoConfig, this); + + registerDao(LocaleMessageBean.class, localeMessageBeanDao); + } + + public void clear() { + localeMessageBeanDaoConfig.clearIdentityScope(); + } + + public LocaleMessageBeanDao getLocaleMessageBeanDao() { + return localeMessageBeanDao; + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java new file mode 100644 index 0000000..f41353a --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java @@ -0,0 +1,199 @@ +package com.casic.br.greendao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.Property; +import org.greenrobot.greendao.internal.DaoConfig; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseStatement; + +import com.casic.br.model.LocaleMessageBean; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table "LOCALE_MESSAGE_BEAN". +*/ +public class LocaleMessageBeanDao extends AbstractDao { + + public static final String TABLENAME = "LOCALE_MESSAGE_BEAN"; + + /** + * Properties of entity LocaleMessageBean.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property MessageId = new Property(1, String.class, "messageId", false, "MESSAGE_ID"); + public final static Property UserId = new Property(2, String.class, "userId", false, "USER_ID"); + public final static Property Title = new Property(3, String.class, "title", false, "TITLE"); + public final static Property Content = new Property(4, String.class, "content", false, "CONTENT"); + public final static Property MessageTime = new Property(5, String.class, "messageTime", false, "MESSAGE_TIME"); + public final static Property IsRead = new Property(6, String.class, "isRead", false, "IS_READ"); + } + + + public LocaleMessageBeanDao(DaoConfig config) { + super(config); + } + + public LocaleMessageBeanDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(Database db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "\"LOCALE_MESSAGE_BEAN\" (" + // + "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "\"MESSAGE_ID\" TEXT UNIQUE ," + // 1: messageId + "\"USER_ID\" TEXT," + // 2: userId + "\"TITLE\" TEXT," + // 3: title + "\"CONTENT\" TEXT," + // 4: content + "\"MESSAGE_TIME\" TEXT," + // 5: messageTime + "\"IS_READ\" TEXT);"); // 6: isRead + } + + /** Drops the underlying database table. */ + public static void dropTable(Database db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"LOCALE_MESSAGE_BEAN\""; + db.execSQL(sql); + } + + @Override + protected final void bindValues(DatabaseStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + protected final void bindValues(SQLiteStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + @Override + public LocaleMessageBean readEntity(Cursor cursor, int offset) { + LocaleMessageBean entity = new LocaleMessageBean( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // messageId + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // userId + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // title + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // content + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // messageTime + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6) // isRead + ); + return entity; + } + + @Override + public void readEntity(Cursor cursor, LocaleMessageBean entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setMessageId(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); + entity.setUserId(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); + entity.setTitle(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); + entity.setContent(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); + entity.setMessageTime(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); + entity.setIsRead(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); + } + + @Override + protected final Long updateKeyAfterInsert(LocaleMessageBean entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + @Override + public Long getKey(LocaleMessageBean entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + @Override + public boolean hasKey(LocaleMessageBean entity) { + return entity.getId() != null; + } + + @Override + protected final boolean isEntityUpdateable() { + return true; + } + +} diff --git a/app/src/main/java/com/casic/br/model/LocaleMessageBean.java b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java new file mode 100644 index 0000000..1341da6 --- /dev/null +++ b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java @@ -0,0 +1,92 @@ +package com.casic.br.model; + +import org.greenrobot.greendao.annotation.Entity; +import org.greenrobot.greendao.annotation.Generated; +import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.Unique; + +@Entity +public class LocaleMessageBean { + @Id(autoincrement = true) + private Long id;//主键自增 + + @Unique + private String messageId; + private String userId; + private String title; + private String content; + private String messageTime; + private String isRead;//0-未读,1-已读 + + @Generated(hash = 22572871) + public LocaleMessageBean(Long id, String messageId, String userId, String title, + String content, String messageTime, String isRead) { + this.id = id; + this.messageId = messageId; + this.userId = userId; + this.title = title; + this.content = content; + this.messageTime = messageTime; + this.isRead = isRead; + } + + @Generated(hash = 1114477439) + public LocaleMessageBean() { + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMessageId() { + return this.messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getUserId() { + return this.userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMessageTime() { + return this.messageTime; + } + + public void setMessageTime(String messageTime) { + this.messageTime = messageTime; + } + + public String getIsRead() { + return this.isRead; + } + + public void setIsRead(String isRead) { + this.isRead = isRead; + } +} diff --git a/app/src/main/java/com/casic/br/utils/BadeHelper.kt b/app/src/main/java/com/casic/br/utils/BadeHelper.kt new file mode 100644 index 0000000..2db01eb --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/BadeHelper.kt @@ -0,0 +1,14 @@ +package com.casic.br.utils + +import android.content.Context +import me.leolin.shortcutbadger.ShortcutBadger + +object BadeHelper { + fun setBadgeNum(context: Context, badgeCount: Int) { + if (badgeCount == 0) { + ShortcutBadger.removeCount(context) + } else { + ShortcutBadger.applyCount(context, badgeCount) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/DataBaseManager.kt b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt new file mode 100644 index 0000000..3918b77 --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt @@ -0,0 +1,69 @@ +package com.casic.br.utils + +import com.casic.br.base.BaseApplication +import com.casic.br.greendao.LocaleMessageBeanDao +import com.casic.br.model.LocaleMessageBean + +class DataBaseManager private constructor() { + + companion object { + //Kotlin委托模式双重锁单例 + val instance: DataBaseManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + DataBaseManager() + } + } + + private val beanDao = BaseApplication.obtainInstance().obtainDaoSession().localeMessageBeanDao + + fun insertLocaleMessage( + messageId: String, userId: String, title: String, + content: String, isRead: String, messageTime: String + ) { + val messageBean = LocaleMessageBean() + messageBean.messageId = messageId + messageBean.userId = userId + messageBean.title = title + messageBean.content = content + messageBean.isRead = isRead + messageBean.messageTime = messageTime + beanDao.insert(messageBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun deleteLocaleMessageById(userId: String, messageId: String) { + val result = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).list() + beanDao.deleteInTx(result) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun updateLocaleMessageById(userId: String, messageId: String) { + val noticeLocaleBean = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).unique() ?: return + noticeLocaleBean.isRead = "1" + beanDao.update(noticeLocaleBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + + fun queryMessageByPage(userId: String, offset: Int): MutableList { + return BaseApplication.obtainInstance().obtainDaoSession() + .queryBuilder(LocaleMessageBean::class.java) + .where(LocaleMessageBeanDao.Properties.UserId.eq(userId)) + .offset(offset * LocaleConstant.PAGE_LIMIT) + .orderDesc(LocaleMessageBeanDao.Properties.MessageTime) + .limit(LocaleConstant.PAGE_LIMIT) + .list() + } + + private fun queryUnReadMessage(): Int { + return beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.IsRead.eq("0") + ).list().size + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt index 737e859..3b8dc98 100644 --- a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt @@ -35,6 +35,7 @@ * ============================================================================================= * */ const val PERMISSIONS_CODE = 999 + const val PAGE_LIMIT = 20 /** * ============================================================================================= diff --git a/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml new file mode 100644 index 0000000..f00d59c --- /dev/null +++ b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dash_line_gray.xml b/app/src/main/res/drawable/dash_line_gray.xml new file mode 100644 index 0000000..61ca4c0 --- /dev/null +++ b/app/src/main/res/drawable/dash_line_gray.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dot_red.xml b/app/src/main/res/drawable/dot_red.xml new file mode 100644 index 0000000..fa97466 --- /dev/null +++ b/app/src/main/res/drawable/dot_red.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml new file mode 100644 index 0000000..ef661b6 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_message_tag.xml b/app/src/main/res/drawable/ic_message_tag.xml new file mode 100644 index 0000000..8650128 --- /dev/null +++ b/app/src/main/res/drawable/ic_message_tag.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/layout/fragment_message.xml b/app/src/main/res/layout/fragment_message.xml index a97ec1b..9537d5b 100644 --- a/app/src/main/res/layout/fragment_message.xml +++ b/app/src/main/res/layout/fragment_message.xml @@ -1,5 +1,6 @@ + android:layout_marginTop="1dp" + android:background="@color/white" + android:orientation="vertical"> + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_mine.xml b/app/src/main/res/layout/fragment_mine.xml index e06099f..d935c02 100644 --- a/app/src/main/res/layout/fragment_mine.xml +++ b/app/src/main/res/layout/fragment_mine.xml @@ -29,8 +29,8 @@ + android:paddingHorizontal="@dimen/dp_10" + android:paddingVertical="@dimen/dp_5"> +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/DaoSession.java b/app/src/main/java/com/casic/br/greendao/DaoSession.java new file mode 100644 index 0000000..18d2242 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoSession.java @@ -0,0 +1,48 @@ +package com.casic.br.greendao; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.casic.br.model.LocaleMessageBean; + +import com.casic.br.greendao.LocaleMessageBeanDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig localeMessageBeanDaoConfig; + + private final LocaleMessageBeanDao localeMessageBeanDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + localeMessageBeanDaoConfig = daoConfigMap.get(LocaleMessageBeanDao.class).clone(); + localeMessageBeanDaoConfig.initIdentityScope(type); + + localeMessageBeanDao = new LocaleMessageBeanDao(localeMessageBeanDaoConfig, this); + + registerDao(LocaleMessageBean.class, localeMessageBeanDao); + } + + public void clear() { + localeMessageBeanDaoConfig.clearIdentityScope(); + } + + public LocaleMessageBeanDao getLocaleMessageBeanDao() { + return localeMessageBeanDao; + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java new file mode 100644 index 0000000..f41353a --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java @@ -0,0 +1,199 @@ +package com.casic.br.greendao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.Property; +import org.greenrobot.greendao.internal.DaoConfig; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseStatement; + +import com.casic.br.model.LocaleMessageBean; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table "LOCALE_MESSAGE_BEAN". +*/ +public class LocaleMessageBeanDao extends AbstractDao { + + public static final String TABLENAME = "LOCALE_MESSAGE_BEAN"; + + /** + * Properties of entity LocaleMessageBean.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property MessageId = new Property(1, String.class, "messageId", false, "MESSAGE_ID"); + public final static Property UserId = new Property(2, String.class, "userId", false, "USER_ID"); + public final static Property Title = new Property(3, String.class, "title", false, "TITLE"); + public final static Property Content = new Property(4, String.class, "content", false, "CONTENT"); + public final static Property MessageTime = new Property(5, String.class, "messageTime", false, "MESSAGE_TIME"); + public final static Property IsRead = new Property(6, String.class, "isRead", false, "IS_READ"); + } + + + public LocaleMessageBeanDao(DaoConfig config) { + super(config); + } + + public LocaleMessageBeanDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(Database db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "\"LOCALE_MESSAGE_BEAN\" (" + // + "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "\"MESSAGE_ID\" TEXT UNIQUE ," + // 1: messageId + "\"USER_ID\" TEXT," + // 2: userId + "\"TITLE\" TEXT," + // 3: title + "\"CONTENT\" TEXT," + // 4: content + "\"MESSAGE_TIME\" TEXT," + // 5: messageTime + "\"IS_READ\" TEXT);"); // 6: isRead + } + + /** Drops the underlying database table. */ + public static void dropTable(Database db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"LOCALE_MESSAGE_BEAN\""; + db.execSQL(sql); + } + + @Override + protected final void bindValues(DatabaseStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + protected final void bindValues(SQLiteStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + @Override + public LocaleMessageBean readEntity(Cursor cursor, int offset) { + LocaleMessageBean entity = new LocaleMessageBean( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // messageId + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // userId + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // title + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // content + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // messageTime + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6) // isRead + ); + return entity; + } + + @Override + public void readEntity(Cursor cursor, LocaleMessageBean entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setMessageId(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); + entity.setUserId(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); + entity.setTitle(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); + entity.setContent(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); + entity.setMessageTime(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); + entity.setIsRead(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); + } + + @Override + protected final Long updateKeyAfterInsert(LocaleMessageBean entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + @Override + public Long getKey(LocaleMessageBean entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + @Override + public boolean hasKey(LocaleMessageBean entity) { + return entity.getId() != null; + } + + @Override + protected final boolean isEntityUpdateable() { + return true; + } + +} diff --git a/app/src/main/java/com/casic/br/model/LocaleMessageBean.java b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java new file mode 100644 index 0000000..1341da6 --- /dev/null +++ b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java @@ -0,0 +1,92 @@ +package com.casic.br.model; + +import org.greenrobot.greendao.annotation.Entity; +import org.greenrobot.greendao.annotation.Generated; +import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.Unique; + +@Entity +public class LocaleMessageBean { + @Id(autoincrement = true) + private Long id;//主键自增 + + @Unique + private String messageId; + private String userId; + private String title; + private String content; + private String messageTime; + private String isRead;//0-未读,1-已读 + + @Generated(hash = 22572871) + public LocaleMessageBean(Long id, String messageId, String userId, String title, + String content, String messageTime, String isRead) { + this.id = id; + this.messageId = messageId; + this.userId = userId; + this.title = title; + this.content = content; + this.messageTime = messageTime; + this.isRead = isRead; + } + + @Generated(hash = 1114477439) + public LocaleMessageBean() { + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMessageId() { + return this.messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getUserId() { + return this.userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMessageTime() { + return this.messageTime; + } + + public void setMessageTime(String messageTime) { + this.messageTime = messageTime; + } + + public String getIsRead() { + return this.isRead; + } + + public void setIsRead(String isRead) { + this.isRead = isRead; + } +} diff --git a/app/src/main/java/com/casic/br/utils/BadeHelper.kt b/app/src/main/java/com/casic/br/utils/BadeHelper.kt new file mode 100644 index 0000000..2db01eb --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/BadeHelper.kt @@ -0,0 +1,14 @@ +package com.casic.br.utils + +import android.content.Context +import me.leolin.shortcutbadger.ShortcutBadger + +object BadeHelper { + fun setBadgeNum(context: Context, badgeCount: Int) { + if (badgeCount == 0) { + ShortcutBadger.removeCount(context) + } else { + ShortcutBadger.applyCount(context, badgeCount) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/DataBaseManager.kt b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt new file mode 100644 index 0000000..3918b77 --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt @@ -0,0 +1,69 @@ +package com.casic.br.utils + +import com.casic.br.base.BaseApplication +import com.casic.br.greendao.LocaleMessageBeanDao +import com.casic.br.model.LocaleMessageBean + +class DataBaseManager private constructor() { + + companion object { + //Kotlin委托模式双重锁单例 + val instance: DataBaseManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + DataBaseManager() + } + } + + private val beanDao = BaseApplication.obtainInstance().obtainDaoSession().localeMessageBeanDao + + fun insertLocaleMessage( + messageId: String, userId: String, title: String, + content: String, isRead: String, messageTime: String + ) { + val messageBean = LocaleMessageBean() + messageBean.messageId = messageId + messageBean.userId = userId + messageBean.title = title + messageBean.content = content + messageBean.isRead = isRead + messageBean.messageTime = messageTime + beanDao.insert(messageBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun deleteLocaleMessageById(userId: String, messageId: String) { + val result = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).list() + beanDao.deleteInTx(result) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun updateLocaleMessageById(userId: String, messageId: String) { + val noticeLocaleBean = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).unique() ?: return + noticeLocaleBean.isRead = "1" + beanDao.update(noticeLocaleBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + + fun queryMessageByPage(userId: String, offset: Int): MutableList { + return BaseApplication.obtainInstance().obtainDaoSession() + .queryBuilder(LocaleMessageBean::class.java) + .where(LocaleMessageBeanDao.Properties.UserId.eq(userId)) + .offset(offset * LocaleConstant.PAGE_LIMIT) + .orderDesc(LocaleMessageBeanDao.Properties.MessageTime) + .limit(LocaleConstant.PAGE_LIMIT) + .list() + } + + private fun queryUnReadMessage(): Int { + return beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.IsRead.eq("0") + ).list().size + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt index 737e859..3b8dc98 100644 --- a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt @@ -35,6 +35,7 @@ * ============================================================================================= * */ const val PERMISSIONS_CODE = 999 + const val PAGE_LIMIT = 20 /** * ============================================================================================= diff --git a/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml new file mode 100644 index 0000000..f00d59c --- /dev/null +++ b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dash_line_gray.xml b/app/src/main/res/drawable/dash_line_gray.xml new file mode 100644 index 0000000..61ca4c0 --- /dev/null +++ b/app/src/main/res/drawable/dash_line_gray.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dot_red.xml b/app/src/main/res/drawable/dot_red.xml new file mode 100644 index 0000000..fa97466 --- /dev/null +++ b/app/src/main/res/drawable/dot_red.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml new file mode 100644 index 0000000..ef661b6 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_message_tag.xml b/app/src/main/res/drawable/ic_message_tag.xml new file mode 100644 index 0000000..8650128 --- /dev/null +++ b/app/src/main/res/drawable/ic_message_tag.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/layout/fragment_message.xml b/app/src/main/res/layout/fragment_message.xml index a97ec1b..9537d5b 100644 --- a/app/src/main/res/layout/fragment_message.xml +++ b/app/src/main/res/layout/fragment_message.xml @@ -1,5 +1,6 @@ + android:layout_marginTop="1dp" + android:background="@color/white" + android:orientation="vertical"> + + + + + + + + + + + +
\ No newline at end of file diff --git a/app/src/main/res/layout/fragment_mine.xml b/app/src/main/res/layout/fragment_mine.xml index e06099f..d935c02 100644 --- a/app/src/main/res/layout/fragment_mine.xml +++ b/app/src/main/res/layout/fragment_mine.xml @@ -29,8 +29,8 @@ + android:paddingHorizontal="@dimen/dp_10" + android:paddingVertical="@dimen/dp_5"> diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/DaoSession.java b/app/src/main/java/com/casic/br/greendao/DaoSession.java new file mode 100644 index 0000000..18d2242 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoSession.java @@ -0,0 +1,48 @@ +package com.casic.br.greendao; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.casic.br.model.LocaleMessageBean; + +import com.casic.br.greendao.LocaleMessageBeanDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig localeMessageBeanDaoConfig; + + private final LocaleMessageBeanDao localeMessageBeanDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + localeMessageBeanDaoConfig = daoConfigMap.get(LocaleMessageBeanDao.class).clone(); + localeMessageBeanDaoConfig.initIdentityScope(type); + + localeMessageBeanDao = new LocaleMessageBeanDao(localeMessageBeanDaoConfig, this); + + registerDao(LocaleMessageBean.class, localeMessageBeanDao); + } + + public void clear() { + localeMessageBeanDaoConfig.clearIdentityScope(); + } + + public LocaleMessageBeanDao getLocaleMessageBeanDao() { + return localeMessageBeanDao; + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java new file mode 100644 index 0000000..f41353a --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java @@ -0,0 +1,199 @@ +package com.casic.br.greendao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.Property; +import org.greenrobot.greendao.internal.DaoConfig; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseStatement; + +import com.casic.br.model.LocaleMessageBean; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table "LOCALE_MESSAGE_BEAN". +*/ +public class LocaleMessageBeanDao extends AbstractDao { + + public static final String TABLENAME = "LOCALE_MESSAGE_BEAN"; + + /** + * Properties of entity LocaleMessageBean.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property MessageId = new Property(1, String.class, "messageId", false, "MESSAGE_ID"); + public final static Property UserId = new Property(2, String.class, "userId", false, "USER_ID"); + public final static Property Title = new Property(3, String.class, "title", false, "TITLE"); + public final static Property Content = new Property(4, String.class, "content", false, "CONTENT"); + public final static Property MessageTime = new Property(5, String.class, "messageTime", false, "MESSAGE_TIME"); + public final static Property IsRead = new Property(6, String.class, "isRead", false, "IS_READ"); + } + + + public LocaleMessageBeanDao(DaoConfig config) { + super(config); + } + + public LocaleMessageBeanDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(Database db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "\"LOCALE_MESSAGE_BEAN\" (" + // + "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "\"MESSAGE_ID\" TEXT UNIQUE ," + // 1: messageId + "\"USER_ID\" TEXT," + // 2: userId + "\"TITLE\" TEXT," + // 3: title + "\"CONTENT\" TEXT," + // 4: content + "\"MESSAGE_TIME\" TEXT," + // 5: messageTime + "\"IS_READ\" TEXT);"); // 6: isRead + } + + /** Drops the underlying database table. */ + public static void dropTable(Database db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"LOCALE_MESSAGE_BEAN\""; + db.execSQL(sql); + } + + @Override + protected final void bindValues(DatabaseStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + protected final void bindValues(SQLiteStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + @Override + public LocaleMessageBean readEntity(Cursor cursor, int offset) { + LocaleMessageBean entity = new LocaleMessageBean( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // messageId + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // userId + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // title + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // content + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // messageTime + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6) // isRead + ); + return entity; + } + + @Override + public void readEntity(Cursor cursor, LocaleMessageBean entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setMessageId(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); + entity.setUserId(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); + entity.setTitle(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); + entity.setContent(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); + entity.setMessageTime(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); + entity.setIsRead(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); + } + + @Override + protected final Long updateKeyAfterInsert(LocaleMessageBean entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + @Override + public Long getKey(LocaleMessageBean entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + @Override + public boolean hasKey(LocaleMessageBean entity) { + return entity.getId() != null; + } + + @Override + protected final boolean isEntityUpdateable() { + return true; + } + +} diff --git a/app/src/main/java/com/casic/br/model/LocaleMessageBean.java b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java new file mode 100644 index 0000000..1341da6 --- /dev/null +++ b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java @@ -0,0 +1,92 @@ +package com.casic.br.model; + +import org.greenrobot.greendao.annotation.Entity; +import org.greenrobot.greendao.annotation.Generated; +import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.Unique; + +@Entity +public class LocaleMessageBean { + @Id(autoincrement = true) + private Long id;//主键自增 + + @Unique + private String messageId; + private String userId; + private String title; + private String content; + private String messageTime; + private String isRead;//0-未读,1-已读 + + @Generated(hash = 22572871) + public LocaleMessageBean(Long id, String messageId, String userId, String title, + String content, String messageTime, String isRead) { + this.id = id; + this.messageId = messageId; + this.userId = userId; + this.title = title; + this.content = content; + this.messageTime = messageTime; + this.isRead = isRead; + } + + @Generated(hash = 1114477439) + public LocaleMessageBean() { + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMessageId() { + return this.messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getUserId() { + return this.userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMessageTime() { + return this.messageTime; + } + + public void setMessageTime(String messageTime) { + this.messageTime = messageTime; + } + + public String getIsRead() { + return this.isRead; + } + + public void setIsRead(String isRead) { + this.isRead = isRead; + } +} diff --git a/app/src/main/java/com/casic/br/utils/BadeHelper.kt b/app/src/main/java/com/casic/br/utils/BadeHelper.kt new file mode 100644 index 0000000..2db01eb --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/BadeHelper.kt @@ -0,0 +1,14 @@ +package com.casic.br.utils + +import android.content.Context +import me.leolin.shortcutbadger.ShortcutBadger + +object BadeHelper { + fun setBadgeNum(context: Context, badgeCount: Int) { + if (badgeCount == 0) { + ShortcutBadger.removeCount(context) + } else { + ShortcutBadger.applyCount(context, badgeCount) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/DataBaseManager.kt b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt new file mode 100644 index 0000000..3918b77 --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt @@ -0,0 +1,69 @@ +package com.casic.br.utils + +import com.casic.br.base.BaseApplication +import com.casic.br.greendao.LocaleMessageBeanDao +import com.casic.br.model.LocaleMessageBean + +class DataBaseManager private constructor() { + + companion object { + //Kotlin委托模式双重锁单例 + val instance: DataBaseManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + DataBaseManager() + } + } + + private val beanDao = BaseApplication.obtainInstance().obtainDaoSession().localeMessageBeanDao + + fun insertLocaleMessage( + messageId: String, userId: String, title: String, + content: String, isRead: String, messageTime: String + ) { + val messageBean = LocaleMessageBean() + messageBean.messageId = messageId + messageBean.userId = userId + messageBean.title = title + messageBean.content = content + messageBean.isRead = isRead + messageBean.messageTime = messageTime + beanDao.insert(messageBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun deleteLocaleMessageById(userId: String, messageId: String) { + val result = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).list() + beanDao.deleteInTx(result) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun updateLocaleMessageById(userId: String, messageId: String) { + val noticeLocaleBean = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).unique() ?: return + noticeLocaleBean.isRead = "1" + beanDao.update(noticeLocaleBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + + fun queryMessageByPage(userId: String, offset: Int): MutableList { + return BaseApplication.obtainInstance().obtainDaoSession() + .queryBuilder(LocaleMessageBean::class.java) + .where(LocaleMessageBeanDao.Properties.UserId.eq(userId)) + .offset(offset * LocaleConstant.PAGE_LIMIT) + .orderDesc(LocaleMessageBeanDao.Properties.MessageTime) + .limit(LocaleConstant.PAGE_LIMIT) + .list() + } + + private fun queryUnReadMessage(): Int { + return beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.IsRead.eq("0") + ).list().size + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt index 737e859..3b8dc98 100644 --- a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt @@ -35,6 +35,7 @@ * ============================================================================================= * */ const val PERMISSIONS_CODE = 999 + const val PAGE_LIMIT = 20 /** * ============================================================================================= diff --git a/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml new file mode 100644 index 0000000..f00d59c --- /dev/null +++ b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dash_line_gray.xml b/app/src/main/res/drawable/dash_line_gray.xml new file mode 100644 index 0000000..61ca4c0 --- /dev/null +++ b/app/src/main/res/drawable/dash_line_gray.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dot_red.xml b/app/src/main/res/drawable/dot_red.xml new file mode 100644 index 0000000..fa97466 --- /dev/null +++ b/app/src/main/res/drawable/dot_red.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml new file mode 100644 index 0000000..ef661b6 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_message_tag.xml b/app/src/main/res/drawable/ic_message_tag.xml new file mode 100644 index 0000000..8650128 --- /dev/null +++ b/app/src/main/res/drawable/ic_message_tag.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/layout/fragment_message.xml b/app/src/main/res/layout/fragment_message.xml index a97ec1b..9537d5b 100644 --- a/app/src/main/res/layout/fragment_message.xml +++ b/app/src/main/res/layout/fragment_message.xml @@ -1,5 +1,6 @@ + android:layout_marginTop="1dp" + android:background="@color/white" + android:orientation="vertical"> + + + + + + + + + + + +
\ No newline at end of file diff --git a/app/src/main/res/layout/fragment_mine.xml b/app/src/main/res/layout/fragment_mine.xml index e06099f..d935c02 100644 --- a/app/src/main/res/layout/fragment_mine.xml +++ b/app/src/main/res/layout/fragment_mine.xml @@ -29,8 +29,8 @@ + android:paddingHorizontal="@dimen/dp_10" + android:paddingVertical="@dimen/dp_5"> diff --git a/app/src/main/res/layout/item_message_rv.xml b/app/src/main/res/layout/item_message_rv.xml new file mode 100644 index 0000000..56535be --- /dev/null +++ b/app/src/main/res/layout/item_message_rv.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index a23d24b..4741037 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 31 @@ -43,6 +44,12 @@ outputFileName = defaultConfig.versionName + ".apk" } } + + greendao { + schemaVersion 1//数据库版本号 + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 + daoPackage 'com.casic.br.greendao'//设置DaoMaster、DaoSession、Dao包名 + } } dependencies { @@ -59,13 +66,13 @@ implementation 'com.qmuiteam:qmui:2.0.0-alpha10' implementation 'com.qmuiteam:arch:0.3.1' //MVVM+LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.9.0' //图片选择框架 @@ -82,9 +89,13 @@ implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' //官方Json解析库 - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.9.0' //上拉加载下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //ZBar(综合Java和C++扫码),生成二维码 implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' + //数据库框架 + implementation 'org.greenrobot:greendao:3.3.0' + //桌面角标 + implementation "me.leolin:ShortcutBadger:1.1.22@aar" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt new file mode 100644 index 0000000..117232a --- /dev/null +++ b/app/src/main/java/com/casic/br/adapter/MessageListAdapter.kt @@ -0,0 +1,68 @@ +package com.casic.br.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.casic.br.R +import com.casic.br.model.LocaleMessageBean + +class MessageListAdapter (context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private var layoutInflater: LayoutInflater = LayoutInflater.from(context) + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder( + layoutInflater.inflate(R.layout.item_message_rv, parent, false) + ) + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + //绑定数据 + val rowsBean = dataRows[position] + holder.dateView.text = rowsBean.messageTime + holder.titleView.text = rowsBean.title + holder.contentView.text = rowsBean.content + val state = if (rowsBean.isRead == "0") { + View.VISIBLE + } else { + View.INVISIBLE + } + holder.readStateView.visibility = state + //绑定事件 + holder.deleteView.setOnClickListener { + listener?.onDeleteClicked(position) + } + + holder.showDetailLayout.setOnClickListener { + listener?.onShowMoreClicked(position) + } + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + var dateView: TextView = view.findViewById(R.id.dateView) + var titleView: TextView = view.findViewById(R.id.titleView) + var contentView: TextView = view.findViewById(R.id.contentView) + var readStateView: TextView = view.findViewById(R.id.readStateView) + + var showDetailLayout: LinearLayout = view.findViewById(R.id.showDetailLayout) + var deleteView: ImageView = view.findViewById(R.id.deleteView) + } + + private var listener: OnItemClickListener? = null + + interface OnItemClickListener { + fun onDeleteClicked(position: Int) + + fun onShowMoreClicked(position: Int) + } + + fun setOnItemClickListener(onClickListener: OnItemClickListener?) { + this.listener = onClickListener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/base/BaseApplication.kt b/app/src/main/java/com/casic/br/base/BaseApplication.kt index ddcd382..d3767fb 100644 --- a/app/src/main/java/com/casic/br/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/br/base/BaseApplication.kt @@ -1,6 +1,8 @@ package com.casic.br.base import android.app.Application +import com.casic.br.greendao.DaoMaster +import com.casic.br.greendao.DaoSession import com.pengxh.kt.lite.utils.SaveKeyValues import kotlin.properties.Delegates @@ -10,11 +12,20 @@ private var instance: BaseApplication by Delegates.notNull() fun obtainInstance() = instance + + private lateinit var daoSession: DaoSession } override fun onCreate() { super.onCreate() instance = this SaveKeyValues.initSharedPreferences(this) + val devOpenHelper = DaoMaster.DevOpenHelper(this, "SmartKitchen.db", null) + val daoMaster = DaoMaster(devOpenHelper.writableDatabase) + daoSession = daoMaster.newSession() + } + + fun obtainDaoSession(): DaoSession { + return daoSession } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt new file mode 100644 index 0000000..bc5fd32 --- /dev/null +++ b/app/src/main/java/com/casic/br/extensions/QMUIEmptyView.kt @@ -0,0 +1,12 @@ +package com.casic.br.extensions + +import android.view.View +import com.qmuiteam.qmui.widget.QMUIEmptyView + +fun QMUIEmptyView.showEmptyPage(onButtonClickListener: View.OnClickListener) { + this.show(false, "抱歉,无法查询到相关记录", null, "重试", onButtonClickListener) +} + +fun QMUIEmptyView.showEmptyPage(title: String, onButtonClickListener: View.OnClickListener) { + this.show(false, title, null, "刷新", onButtonClickListener) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt index 76c5414..46d52bd 100644 --- a/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt +++ b/app/src/main/java/com/casic/br/fragment/MessagePageFragment.kt @@ -1,21 +1,135 @@ package com.casic.br.fragment +import android.os.CountDownTimer +import android.os.Handler +import androidx.recyclerview.widget.DividerItemDecoration import com.casic.br.R +import com.casic.br.adapter.MessageListAdapter +import com.casic.br.extensions.showEmptyPage +import com.casic.br.model.LocaleMessageBean +import com.casic.br.utils.DataBaseManager import com.pengxh.kt.lite.base.KotlinBaseFragment +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import kotlinx.android.synthetic.main.fragment_message.* +import kotlinx.android.synthetic.main.fragment_mine.* +import kotlinx.android.synthetic.main.include_empty_view.* +import kotlinx.android.synthetic.main.include_main_title.* class MessagePageFragment : KotlinBaseFragment() { + private lateinit var weakReferenceHandler: WeakReferenceHandler + private lateinit var messageAdapter: MessageListAdapter + private var dataBeans: MutableList = ArrayList() + private var pageIndex = 0 // 本地数据库分页从0开始 + private var isRefresh = false + private var isLoadMore = false + private var userId = "" + override fun initLayoutView(): Int = R.layout.fragment_message override fun setupTopBarLayout() { - + leftTitleView.text = "消息" } override fun initData() { - + weakReferenceHandler = WeakReferenceHandler(callback) } override fun initEvent() { + messageLayout.setOnRefreshListener { + isRefresh = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + isRefresh = false + dataBeans.clear() + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + + it.finishRefresh() + weakReferenceHandler.sendEmptyMessage(2022070401) + } + }.start() + } + + messageLayout.setOnLoadMoreListener { + isLoadMore = true + object : CountDownTimer(1000, 500) { + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + isLoadMore = false + pageIndex++ + dataBeans.addAll( + DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + ) + it.finishLoadMore() + weakReferenceHandler.sendEmptyMessage(2022082301) + } + }.start() + } + } + + override fun onResume() { + //默认加载第一页 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + super.onResume() + } + + private val callback = Handler.Callback { + if (it.what == 2022082301) { + if (isRefresh || isLoadMore) { + messageAdapter.notifyDataSetChanged() + } else { + if (dataBeans.size == 0) { + emptyView!!.showEmptyPage("没有任何报警通知") { + pageIndex = 0 + dataBeans = DataBaseManager.instance.queryMessageByPage(userId, pageIndex) + weakReferenceHandler.sendEmptyMessage(2022082301) + } + } else { + emptyView!!.hide() + messageAdapter = MessageListAdapter(requireContext(), dataBeans) + settingsRecyclerView.addItemDecoration( + DividerItemDecoration( + requireContext(), DividerItemDecoration.VERTICAL + ) + ) + messageRecyclerView.adapter = messageAdapter + messageAdapter.setOnItemClickListener(object : + MessageListAdapter.OnItemClickListener { + override fun onDeleteClicked(position: Int) { +// DataBaseManager.instance.deleteLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// dataBeans.removeAt(position) +// messageAdapter.notifyItemRemoved(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + + override fun onShowMoreClicked(position: Int) { +// deviceViewModel.obtainDeviceDetail(dataBeans[position].deviceCode) +// //更改数据库里通知状态 +// DataBaseManager.instance.updateLocaleMessageById( +// userId, dataBeans[position].messageId +// ) +// messageAdapter.notifyItemChanged(position) +// messageAdapter.notifyItemRangeChanged( +// position, dataBeans.size - position +// ) + } + }) + } + } + } + true } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/greendao/DaoMaster.java b/app/src/main/java/com/casic/br/greendao/DaoMaster.java new file mode 100644 index 0000000..05390e0 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoMaster.java @@ -0,0 +1,96 @@ +package com.casic.br.greendao; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.util.Log; + +import org.greenrobot.greendao.AbstractDaoMaster; +import org.greenrobot.greendao.database.StandardDatabase; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseOpenHelper; +import org.greenrobot.greendao.identityscope.IdentityScopeType; + + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * Master of DAO (schema version 1): knows all DAOs. + */ +public class DaoMaster extends AbstractDaoMaster { + public static final int SCHEMA_VERSION = 1; + + /** Creates underlying database table using DAOs. */ + public static void createAllTables(Database db, boolean ifNotExists) { + LocaleMessageBeanDao.createTable(db, ifNotExists); + } + + /** Drops underlying database table using DAOs. */ + public static void dropAllTables(Database db, boolean ifExists) { + LocaleMessageBeanDao.dropTable(db, ifExists); + } + + /** + * WARNING: Drops all table on Upgrade! Use only during development. + * Convenience method using a {@link DevOpenHelper}. + */ + public static DaoSession newDevSession(Context context, String name) { + Database db = new DevOpenHelper(context, name).getWritableDb(); + DaoMaster daoMaster = new DaoMaster(db); + return daoMaster.newSession(); + } + + public DaoMaster(SQLiteDatabase db) { + this(new StandardDatabase(db)); + } + + public DaoMaster(Database db) { + super(db, SCHEMA_VERSION); + registerDaoClass(LocaleMessageBeanDao.class); + } + + public DaoSession newSession() { + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); + } + + public DaoSession newSession(IdentityScopeType type) { + return new DaoSession(db, type, daoConfigMap); + } + + /** + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - + */ + public static abstract class OpenHelper extends DatabaseOpenHelper { + public OpenHelper(Context context, String name) { + super(context, name, SCHEMA_VERSION); + } + + public OpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory, SCHEMA_VERSION); + } + + @Override + public void onCreate(Database db) { + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); + createAllTables(db, false); + } + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevOpenHelper extends OpenHelper { + public DevOpenHelper(Context context, String name) { + super(context, name); + } + + public DevOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(Database db, int oldVersion, int newVersion) { + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/DaoSession.java b/app/src/main/java/com/casic/br/greendao/DaoSession.java new file mode 100644 index 0000000..18d2242 --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/DaoSession.java @@ -0,0 +1,48 @@ +package com.casic.br.greendao; + +import java.util.Map; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.AbstractDaoSession; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.identityscope.IdentityScopeType; +import org.greenrobot.greendao.internal.DaoConfig; + +import com.casic.br.model.LocaleMessageBean; + +import com.casic.br.greendao.LocaleMessageBeanDao; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. + +/** + * {@inheritDoc} + * + * @see org.greenrobot.greendao.AbstractDaoSession + */ +public class DaoSession extends AbstractDaoSession { + + private final DaoConfig localeMessageBeanDaoConfig; + + private final LocaleMessageBeanDao localeMessageBeanDao; + + public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> + daoConfigMap) { + super(db); + + localeMessageBeanDaoConfig = daoConfigMap.get(LocaleMessageBeanDao.class).clone(); + localeMessageBeanDaoConfig.initIdentityScope(type); + + localeMessageBeanDao = new LocaleMessageBeanDao(localeMessageBeanDaoConfig, this); + + registerDao(LocaleMessageBean.class, localeMessageBeanDao); + } + + public void clear() { + localeMessageBeanDaoConfig.clearIdentityScope(); + } + + public LocaleMessageBeanDao getLocaleMessageBeanDao() { + return localeMessageBeanDao; + } + +} diff --git a/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java new file mode 100644 index 0000000..f41353a --- /dev/null +++ b/app/src/main/java/com/casic/br/greendao/LocaleMessageBeanDao.java @@ -0,0 +1,199 @@ +package com.casic.br.greendao; + +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; + +import org.greenrobot.greendao.AbstractDao; +import org.greenrobot.greendao.Property; +import org.greenrobot.greendao.internal.DaoConfig; +import org.greenrobot.greendao.database.Database; +import org.greenrobot.greendao.database.DatabaseStatement; + +import com.casic.br.model.LocaleMessageBean; + +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. +/** + * DAO for table "LOCALE_MESSAGE_BEAN". +*/ +public class LocaleMessageBeanDao extends AbstractDao { + + public static final String TABLENAME = "LOCALE_MESSAGE_BEAN"; + + /** + * Properties of entity LocaleMessageBean.
+ * Can be used for QueryBuilder and for referencing column names. + */ + public static class Properties { + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); + public final static Property MessageId = new Property(1, String.class, "messageId", false, "MESSAGE_ID"); + public final static Property UserId = new Property(2, String.class, "userId", false, "USER_ID"); + public final static Property Title = new Property(3, String.class, "title", false, "TITLE"); + public final static Property Content = new Property(4, String.class, "content", false, "CONTENT"); + public final static Property MessageTime = new Property(5, String.class, "messageTime", false, "MESSAGE_TIME"); + public final static Property IsRead = new Property(6, String.class, "isRead", false, "IS_READ"); + } + + + public LocaleMessageBeanDao(DaoConfig config) { + super(config); + } + + public LocaleMessageBeanDao(DaoConfig config, DaoSession daoSession) { + super(config, daoSession); + } + + /** Creates the underlying database table. */ + public static void createTable(Database db, boolean ifNotExists) { + String constraint = ifNotExists? "IF NOT EXISTS ": ""; + db.execSQL("CREATE TABLE " + constraint + "\"LOCALE_MESSAGE_BEAN\" (" + // + "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id + "\"MESSAGE_ID\" TEXT UNIQUE ," + // 1: messageId + "\"USER_ID\" TEXT," + // 2: userId + "\"TITLE\" TEXT," + // 3: title + "\"CONTENT\" TEXT," + // 4: content + "\"MESSAGE_TIME\" TEXT," + // 5: messageTime + "\"IS_READ\" TEXT);"); // 6: isRead + } + + /** Drops the underlying database table. */ + public static void dropTable(Database db, boolean ifExists) { + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"LOCALE_MESSAGE_BEAN\""; + db.execSQL(sql); + } + + @Override + protected final void bindValues(DatabaseStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + protected final void bindValues(SQLiteStatement stmt, LocaleMessageBean entity) { + stmt.clearBindings(); + + Long id = entity.getId(); + if (id != null) { + stmt.bindLong(1, id); + } + + String messageId = entity.getMessageId(); + if (messageId != null) { + stmt.bindString(2, messageId); + } + + String userId = entity.getUserId(); + if (userId != null) { + stmt.bindString(3, userId); + } + + String title = entity.getTitle(); + if (title != null) { + stmt.bindString(4, title); + } + + String content = entity.getContent(); + if (content != null) { + stmt.bindString(5, content); + } + + String messageTime = entity.getMessageTime(); + if (messageTime != null) { + stmt.bindString(6, messageTime); + } + + String isRead = entity.getIsRead(); + if (isRead != null) { + stmt.bindString(7, isRead); + } + } + + @Override + public Long readKey(Cursor cursor, int offset) { + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); + } + + @Override + public LocaleMessageBean readEntity(Cursor cursor, int offset) { + LocaleMessageBean entity = new LocaleMessageBean( // + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // messageId + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // userId + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // title + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // content + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // messageTime + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6) // isRead + ); + return entity; + } + + @Override + public void readEntity(Cursor cursor, LocaleMessageBean entity, int offset) { + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); + entity.setMessageId(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); + entity.setUserId(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); + entity.setTitle(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); + entity.setContent(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); + entity.setMessageTime(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); + entity.setIsRead(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); + } + + @Override + protected final Long updateKeyAfterInsert(LocaleMessageBean entity, long rowId) { + entity.setId(rowId); + return rowId; + } + + @Override + public Long getKey(LocaleMessageBean entity) { + if(entity != null) { + return entity.getId(); + } else { + return null; + } + } + + @Override + public boolean hasKey(LocaleMessageBean entity) { + return entity.getId() != null; + } + + @Override + protected final boolean isEntityUpdateable() { + return true; + } + +} diff --git a/app/src/main/java/com/casic/br/model/LocaleMessageBean.java b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java new file mode 100644 index 0000000..1341da6 --- /dev/null +++ b/app/src/main/java/com/casic/br/model/LocaleMessageBean.java @@ -0,0 +1,92 @@ +package com.casic.br.model; + +import org.greenrobot.greendao.annotation.Entity; +import org.greenrobot.greendao.annotation.Generated; +import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.Unique; + +@Entity +public class LocaleMessageBean { + @Id(autoincrement = true) + private Long id;//主键自增 + + @Unique + private String messageId; + private String userId; + private String title; + private String content; + private String messageTime; + private String isRead;//0-未读,1-已读 + + @Generated(hash = 22572871) + public LocaleMessageBean(Long id, String messageId, String userId, String title, + String content, String messageTime, String isRead) { + this.id = id; + this.messageId = messageId; + this.userId = userId; + this.title = title; + this.content = content; + this.messageTime = messageTime; + this.isRead = isRead; + } + + @Generated(hash = 1114477439) + public LocaleMessageBean() { + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMessageId() { + return this.messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getUserId() { + return this.userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMessageTime() { + return this.messageTime; + } + + public void setMessageTime(String messageTime) { + this.messageTime = messageTime; + } + + public String getIsRead() { + return this.isRead; + } + + public void setIsRead(String isRead) { + this.isRead = isRead; + } +} diff --git a/app/src/main/java/com/casic/br/utils/BadeHelper.kt b/app/src/main/java/com/casic/br/utils/BadeHelper.kt new file mode 100644 index 0000000..2db01eb --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/BadeHelper.kt @@ -0,0 +1,14 @@ +package com.casic.br.utils + +import android.content.Context +import me.leolin.shortcutbadger.ShortcutBadger + +object BadeHelper { + fun setBadgeNum(context: Context, badgeCount: Int) { + if (badgeCount == 0) { + ShortcutBadger.removeCount(context) + } else { + ShortcutBadger.applyCount(context, badgeCount) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/DataBaseManager.kt b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt new file mode 100644 index 0000000..3918b77 --- /dev/null +++ b/app/src/main/java/com/casic/br/utils/DataBaseManager.kt @@ -0,0 +1,69 @@ +package com.casic.br.utils + +import com.casic.br.base.BaseApplication +import com.casic.br.greendao.LocaleMessageBeanDao +import com.casic.br.model.LocaleMessageBean + +class DataBaseManager private constructor() { + + companion object { + //Kotlin委托模式双重锁单例 + val instance: DataBaseManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + DataBaseManager() + } + } + + private val beanDao = BaseApplication.obtainInstance().obtainDaoSession().localeMessageBeanDao + + fun insertLocaleMessage( + messageId: String, userId: String, title: String, + content: String, isRead: String, messageTime: String + ) { + val messageBean = LocaleMessageBean() + messageBean.messageId = messageId + messageBean.userId = userId + messageBean.title = title + messageBean.content = content + messageBean.isRead = isRead + messageBean.messageTime = messageTime + beanDao.insert(messageBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun deleteLocaleMessageById(userId: String, messageId: String) { + val result = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).list() + beanDao.deleteInTx(result) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + fun updateLocaleMessageById(userId: String, messageId: String) { + val noticeLocaleBean = beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.MessageId.eq(messageId) + ).unique() ?: return + noticeLocaleBean.isRead = "1" + beanDao.update(noticeLocaleBean) + //角标设置 + BadeHelper.setBadgeNum(BaseApplication.obtainInstance(), queryUnReadMessage()) + } + + + fun queryMessageByPage(userId: String, offset: Int): MutableList { + return BaseApplication.obtainInstance().obtainDaoSession() + .queryBuilder(LocaleMessageBean::class.java) + .where(LocaleMessageBeanDao.Properties.UserId.eq(userId)) + .offset(offset * LocaleConstant.PAGE_LIMIT) + .orderDesc(LocaleMessageBeanDao.Properties.MessageTime) + .limit(LocaleConstant.PAGE_LIMIT) + .list() + } + + private fun queryUnReadMessage(): Int { + return beanDao.queryBuilder().where( + LocaleMessageBeanDao.Properties.IsRead.eq("0") + ).list().size + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt index 737e859..3b8dc98 100644 --- a/app/src/main/java/com/casic/br/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/br/utils/LocaleConstant.kt @@ -35,6 +35,7 @@ * ============================================================================================= * */ const val PERMISSIONS_CODE = 999 + const val PAGE_LIMIT = 20 /** * ============================================================================================= diff --git a/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml new file mode 100644 index 0000000..f00d59c --- /dev/null +++ b/app/src/main/res/drawable/bg_solid_layout_white_radius_10.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dash_line_gray.xml b/app/src/main/res/drawable/dash_line_gray.xml new file mode 100644 index 0000000..61ca4c0 --- /dev/null +++ b/app/src/main/res/drawable/dash_line_gray.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dot_red.xml b/app/src/main/res/drawable/dot_red.xml new file mode 100644 index 0000000..fa97466 --- /dev/null +++ b/app/src/main/res/drawable/dot_red.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml new file mode 100644 index 0000000..ef661b6 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_message_tag.xml b/app/src/main/res/drawable/ic_message_tag.xml new file mode 100644 index 0000000..8650128 --- /dev/null +++ b/app/src/main/res/drawable/ic_message_tag.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/layout/fragment_message.xml b/app/src/main/res/layout/fragment_message.xml index a97ec1b..9537d5b 100644 --- a/app/src/main/res/layout/fragment_message.xml +++ b/app/src/main/res/layout/fragment_message.xml @@ -1,5 +1,6 @@ + android:layout_marginTop="1dp" + android:background="@color/white" + android:orientation="vertical"> + + + + + + + + + + + +
\ No newline at end of file diff --git a/app/src/main/res/layout/fragment_mine.xml b/app/src/main/res/layout/fragment_mine.xml index e06099f..d935c02 100644 --- a/app/src/main/res/layout/fragment_mine.xml +++ b/app/src/main/res/layout/fragment_mine.xml @@ -29,8 +29,8 @@ + android:paddingHorizontal="@dimen/dp_10" + android:paddingVertical="@dimen/dp_5"> diff --git a/app/src/main/res/layout/item_message_rv.xml b/app/src/main/res/layout/item_message_rv.xml new file mode 100644 index 0000000..56535be --- /dev/null +++ b/app/src/main/res/layout/item_message_rv.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7408bb3..ff2cac1 100644 --- a/build.gradle +++ b/build.gradle @@ -8,6 +8,7 @@ dependencies { classpath 'com.android.tools.build:gradle:3.6.4' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'org.greenrobot:greendao-gradle-plugin:3.3.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files