diff --git a/app/build.gradle b/app/build.gradle index b3a6cfc..d06afef 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -49,6 +49,7 @@ implementation 'com.gyf.immersionbar:immersionbar:3.0.0' //MVVM+LiveData implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 @@ -82,4 +83,6 @@ implementation 'com.just.agentweb:agentweb-androidx:4.1.4' //日期选择器 implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' + //Html解析,爬虫 + implementation 'org.jsoup:jsoup:1.14.3' } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index b3a6cfc..d06afef 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -49,6 +49,7 @@ implementation 'com.gyf.immersionbar:immersionbar:3.0.0' //MVVM+LiveData implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 @@ -82,4 +83,6 @@ implementation 'com.just.agentweb:agentweb-androidx:4.1.4' //日期选择器 implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' + //Html解析,爬虫 + implementation 'org.jsoup:jsoup:1.14.3' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt b/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt index d6af0f1..62d6a11 100644 --- a/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt +++ b/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt @@ -9,22 +9,11 @@ */ class BannerImageModel { /** - * success : true - * code : 200 - * message : 请求成功 - * data : [{"imageTitle":"测试标题1","imageLink":"https://images.pexels.com/photos/1036808/pexels-photo-1036808.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题2","imageLink":"https://images.pexels.com/photos/796602/pexels-photo-796602.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题3","imageLink":"https://images.pexels.com/photos/1109543/pexels-photo-1109543.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题4","imageLink":"https://images.pexels.com/photos/296115/pexels-photo-296115.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题5","imageLink":"https://images.pexels.com/photos/4158/apple-iphone-smartphone-desk.jpg?auto=compress&cs=tinysrgb&dpr=1&w=500"}] + * imageTitle : 亚洲首例300级深水导管架“海基一号”成... + * imageLink : https://www.cnoocengineering.com/picture/0/9c577a461ef24aafb9b1e06b8387f0ce.jpg + * webPageLink : /art/2022/4/12/art_29351_15325995.html */ - var isSuccess = false - var code = 0 - var message: String? = null - var data: List? = null - - class DataBean { - /** - * imageTitle : 测试标题1 - * imageLink : https://images.pexels.com/photos/1036808/pexels-photo-1036808.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500 - */ - var imageTitle: String? = null - var imageLink: String? = null - } + var imageTitle: String? = null + var imageLink: String? = null + var webPageLink: String? = null } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index b3a6cfc..d06afef 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -49,6 +49,7 @@ implementation 'com.gyf.immersionbar:immersionbar:3.0.0' //MVVM+LiveData implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 @@ -82,4 +83,6 @@ implementation 'com.just.agentweb:agentweb-androidx:4.1.4' //日期选择器 implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' + //Html解析,爬虫 + implementation 'org.jsoup:jsoup:1.14.3' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt b/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt index d6af0f1..62d6a11 100644 --- a/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt +++ b/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt @@ -9,22 +9,11 @@ */ class BannerImageModel { /** - * success : true - * code : 200 - * message : 请求成功 - * data : [{"imageTitle":"测试标题1","imageLink":"https://images.pexels.com/photos/1036808/pexels-photo-1036808.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题2","imageLink":"https://images.pexels.com/photos/796602/pexels-photo-796602.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题3","imageLink":"https://images.pexels.com/photos/1109543/pexels-photo-1109543.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题4","imageLink":"https://images.pexels.com/photos/296115/pexels-photo-296115.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题5","imageLink":"https://images.pexels.com/photos/4158/apple-iphone-smartphone-desk.jpg?auto=compress&cs=tinysrgb&dpr=1&w=500"}] + * imageTitle : 亚洲首例300级深水导管架“海基一号”成... + * imageLink : https://www.cnoocengineering.com/picture/0/9c577a461ef24aafb9b1e06b8387f0ce.jpg + * webPageLink : /art/2022/4/12/art_29351_15325995.html */ - var isSuccess = false - var code = 0 - var message: String? = null - var data: List? = null - - class DataBean { - /** - * imageTitle : 测试标题1 - * imageLink : https://images.pexels.com/photos/1036808/pexels-photo-1036808.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500 - */ - var imageTitle: String? = null - var imageLink: String? = null - } + var imageTitle: String? = null + var imageLink: String? = null + var webPageLink: String? = null } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt index cb85f80..da8d67c 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt @@ -34,4 +34,23 @@ const val USER_DEVICE_TYPE = "userDeviceType" const val CANCEL_ALARM_ACTION = "cancelAlarm" const val AREA_ID = "110000" + const val BANNER_MODEL = "bannerModel" + + //首页Banner图目的网址 + /** + * 公司网站 + * */ + const val BASE_URL = "https://www.cnoocengineering.com/" + + /** + * 公司大事记 + * */ + val NEWS_PAGE = + arrayOf( + BASE_URL + "art/2022/4/12/art_29351_15325995.html", + BASE_URL + "art/2022/3/23/art_29351_15325404.html", + BASE_URL + "art/2022/3/18/art_29351_15325302.html", + BASE_URL + "art/2022/3/4/art_29351_15324210.html", + BASE_URL + "art/2022/2/28/art_29351_15324078.html" + ) } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index b3a6cfc..d06afef 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -49,6 +49,7 @@ implementation 'com.gyf.immersionbar:immersionbar:3.0.0' //MVVM+LiveData implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 @@ -82,4 +83,6 @@ implementation 'com.just.agentweb:agentweb-androidx:4.1.4' //日期选择器 implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' + //Html解析,爬虫 + implementation 'org.jsoup:jsoup:1.14.3' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt b/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt index d6af0f1..62d6a11 100644 --- a/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt +++ b/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt @@ -9,22 +9,11 @@ */ class BannerImageModel { /** - * success : true - * code : 200 - * message : 请求成功 - * data : [{"imageTitle":"测试标题1","imageLink":"https://images.pexels.com/photos/1036808/pexels-photo-1036808.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题2","imageLink":"https://images.pexels.com/photos/796602/pexels-photo-796602.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题3","imageLink":"https://images.pexels.com/photos/1109543/pexels-photo-1109543.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题4","imageLink":"https://images.pexels.com/photos/296115/pexels-photo-296115.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题5","imageLink":"https://images.pexels.com/photos/4158/apple-iphone-smartphone-desk.jpg?auto=compress&cs=tinysrgb&dpr=1&w=500"}] + * imageTitle : 亚洲首例300级深水导管架“海基一号”成... + * imageLink : https://www.cnoocengineering.com/picture/0/9c577a461ef24aafb9b1e06b8387f0ce.jpg + * webPageLink : /art/2022/4/12/art_29351_15325995.html */ - var isSuccess = false - var code = 0 - var message: String? = null - var data: List? = null - - class DataBean { - /** - * imageTitle : 测试标题1 - * imageLink : https://images.pexels.com/photos/1036808/pexels-photo-1036808.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500 - */ - var imageTitle: String? = null - var imageLink: String? = null - } + var imageTitle: String? = null + var imageLink: String? = null + var webPageLink: String? = null } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt index cb85f80..da8d67c 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt @@ -34,4 +34,23 @@ const val USER_DEVICE_TYPE = "userDeviceType" const val CANCEL_ALARM_ACTION = "cancelAlarm" const val AREA_ID = "110000" + const val BANNER_MODEL = "bannerModel" + + //首页Banner图目的网址 + /** + * 公司网站 + * */ + const val BASE_URL = "https://www.cnoocengineering.com/" + + /** + * 公司大事记 + * */ + val NEWS_PAGE = + arrayOf( + BASE_URL + "art/2022/4/12/art_29351_15325995.html", + BASE_URL + "art/2022/3/23/art_29351_15325404.html", + BASE_URL + "art/2022/3/18/art_29351_15325302.html", + BASE_URL + "art/2022/3/4/art_29351_15324210.html", + BASE_URL + "art/2022/2/28/art_29351_15324078.html" + ) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/TimeOrDateUtil.kt b/app/src/main/java/com/casic/qd/smartwell/utils/TimeOrDateUtil.kt deleted file mode 100644 index 35ca1b0..0000000 --- a/app/src/main/java/com/casic/qd/smartwell/utils/TimeOrDateUtil.kt +++ /dev/null @@ -1,113 +0,0 @@ -package com.casic.qd.smartwell.utils - -import java.text.ParseException -import java.text.SimpleDateFormat -import java.util.* - -/** - * @author : Pengxh - * @time : 2021/4/15 16:54 - * @email : 290677893@qq.com - */ -object TimeOrDateUtil { - private var dateFormat: SimpleDateFormat? = null - - /** - * 获取年月区间,[2022-02-01,2022-02-28] - */ - @Throws(ParseException::class) - fun timestampToMonth(millSeconds: Long): Array { - dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA) - //先判断是否在当月 - return if (isInThisMonth(millSeconds)) { - val date = Date() - val calendar = Calendar.getInstance() - calendar.time = date - //获得本月第一天 - calendar.add(Calendar.MONTH, 0) - calendar[Calendar.DAY_OF_MONTH] = 1 - val firstDay = dateFormat!!.format(calendar.time) - date.time = millSeconds - val currentDay = dateFormat!!.format(date) - arrayOf(firstDay, currentDay) - } else { - val dateValue = dateFormat!!.format(Date(millSeconds)) - val date = dateFormat!!.parse(dateValue) - val calendar = Calendar.getInstance() - calendar.time = date - //获得月第一天 - calendar.add(Calendar.MONTH, 0) - calendar[Calendar.DAY_OF_MONTH] = 1 - val firstDay = dateFormat!!.format(calendar.time) - val year = calendar[Calendar.YEAR] - val m = calendar[Calendar.MONTH] + 1 - val month: String = if (m < 10) { - "0$m" - } else { - m.toString() - } - val maxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH) - arrayOf(firstDay, "$year-$month-$maxDay") - } - } - - /** - * 判断时间是否在本月之内 - */ - private fun isInThisMonth(millSeconds: Long): Boolean { - //所选时间对应的月份 - val dateFormat = SimpleDateFormat("MM", Locale.CHINA) - val selectedMonth = dateFormat.format(Date(millSeconds)) - //系统时间对应的月份 - val systemMonth = dateFormat.format(Date(System.currentTimeMillis())) - return selectedMonth == systemMonth - } - - /** - * 时间戳转年月日时分秒 - */ - fun timestampToCompleteDate(millSeconds: Long): String { - dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转年月日 - */ - fun timestampToDate(millSeconds: Long): String { - dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转年月 - */ - fun timestampToYearMonth(millSeconds: Long): String { - dateFormat = SimpleDateFormat("yyyy年MM月", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转时分秒 - */ - fun timestampToTime(millSeconds: Long): String { - dateFormat = SimpleDateFormat("HH:mm:ss", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转时分 - */ - fun minuteToTime(millSeconds: Long): String { - dateFormat = SimpleDateFormat("HH:mm", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转分秒 - */ - fun millsToTime(millSeconds: Long): String { - dateFormat = SimpleDateFormat("mm:ss", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } -} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index b3a6cfc..d06afef 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -49,6 +49,7 @@ implementation 'com.gyf.immersionbar:immersionbar:3.0.0' //MVVM+LiveData implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 @@ -82,4 +83,6 @@ implementation 'com.just.agentweb:agentweb-androidx:4.1.4' //日期选择器 implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' + //Html解析,爬虫 + implementation 'org.jsoup:jsoup:1.14.3' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt b/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt index d6af0f1..62d6a11 100644 --- a/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt +++ b/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt @@ -9,22 +9,11 @@ */ class BannerImageModel { /** - * success : true - * code : 200 - * message : 请求成功 - * data : [{"imageTitle":"测试标题1","imageLink":"https://images.pexels.com/photos/1036808/pexels-photo-1036808.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题2","imageLink":"https://images.pexels.com/photos/796602/pexels-photo-796602.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题3","imageLink":"https://images.pexels.com/photos/1109543/pexels-photo-1109543.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题4","imageLink":"https://images.pexels.com/photos/296115/pexels-photo-296115.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题5","imageLink":"https://images.pexels.com/photos/4158/apple-iphone-smartphone-desk.jpg?auto=compress&cs=tinysrgb&dpr=1&w=500"}] + * imageTitle : 亚洲首例300级深水导管架“海基一号”成... + * imageLink : https://www.cnoocengineering.com/picture/0/9c577a461ef24aafb9b1e06b8387f0ce.jpg + * webPageLink : /art/2022/4/12/art_29351_15325995.html */ - var isSuccess = false - var code = 0 - var message: String? = null - var data: List? = null - - class DataBean { - /** - * imageTitle : 测试标题1 - * imageLink : https://images.pexels.com/photos/1036808/pexels-photo-1036808.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500 - */ - var imageTitle: String? = null - var imageLink: String? = null - } + var imageTitle: String? = null + var imageLink: String? = null + var webPageLink: String? = null } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt index cb85f80..da8d67c 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt @@ -34,4 +34,23 @@ const val USER_DEVICE_TYPE = "userDeviceType" const val CANCEL_ALARM_ACTION = "cancelAlarm" const val AREA_ID = "110000" + const val BANNER_MODEL = "bannerModel" + + //首页Banner图目的网址 + /** + * 公司网站 + * */ + const val BASE_URL = "https://www.cnoocengineering.com/" + + /** + * 公司大事记 + * */ + val NEWS_PAGE = + arrayOf( + BASE_URL + "art/2022/4/12/art_29351_15325995.html", + BASE_URL + "art/2022/3/23/art_29351_15325404.html", + BASE_URL + "art/2022/3/18/art_29351_15325302.html", + BASE_URL + "art/2022/3/4/art_29351_15324210.html", + BASE_URL + "art/2022/2/28/art_29351_15324078.html" + ) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/TimeOrDateUtil.kt b/app/src/main/java/com/casic/qd/smartwell/utils/TimeOrDateUtil.kt deleted file mode 100644 index 35ca1b0..0000000 --- a/app/src/main/java/com/casic/qd/smartwell/utils/TimeOrDateUtil.kt +++ /dev/null @@ -1,113 +0,0 @@ -package com.casic.qd.smartwell.utils - -import java.text.ParseException -import java.text.SimpleDateFormat -import java.util.* - -/** - * @author : Pengxh - * @time : 2021/4/15 16:54 - * @email : 290677893@qq.com - */ -object TimeOrDateUtil { - private var dateFormat: SimpleDateFormat? = null - - /** - * 获取年月区间,[2022-02-01,2022-02-28] - */ - @Throws(ParseException::class) - fun timestampToMonth(millSeconds: Long): Array { - dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA) - //先判断是否在当月 - return if (isInThisMonth(millSeconds)) { - val date = Date() - val calendar = Calendar.getInstance() - calendar.time = date - //获得本月第一天 - calendar.add(Calendar.MONTH, 0) - calendar[Calendar.DAY_OF_MONTH] = 1 - val firstDay = dateFormat!!.format(calendar.time) - date.time = millSeconds - val currentDay = dateFormat!!.format(date) - arrayOf(firstDay, currentDay) - } else { - val dateValue = dateFormat!!.format(Date(millSeconds)) - val date = dateFormat!!.parse(dateValue) - val calendar = Calendar.getInstance() - calendar.time = date - //获得月第一天 - calendar.add(Calendar.MONTH, 0) - calendar[Calendar.DAY_OF_MONTH] = 1 - val firstDay = dateFormat!!.format(calendar.time) - val year = calendar[Calendar.YEAR] - val m = calendar[Calendar.MONTH] + 1 - val month: String = if (m < 10) { - "0$m" - } else { - m.toString() - } - val maxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH) - arrayOf(firstDay, "$year-$month-$maxDay") - } - } - - /** - * 判断时间是否在本月之内 - */ - private fun isInThisMonth(millSeconds: Long): Boolean { - //所选时间对应的月份 - val dateFormat = SimpleDateFormat("MM", Locale.CHINA) - val selectedMonth = dateFormat.format(Date(millSeconds)) - //系统时间对应的月份 - val systemMonth = dateFormat.format(Date(System.currentTimeMillis())) - return selectedMonth == systemMonth - } - - /** - * 时间戳转年月日时分秒 - */ - fun timestampToCompleteDate(millSeconds: Long): String { - dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转年月日 - */ - fun timestampToDate(millSeconds: Long): String { - dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转年月 - */ - fun timestampToYearMonth(millSeconds: Long): String { - dateFormat = SimpleDateFormat("yyyy年MM月", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转时分秒 - */ - fun timestampToTime(millSeconds: Long): String { - dateFormat = SimpleDateFormat("HH:mm:ss", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转时分 - */ - fun minuteToTime(millSeconds: Long): String { - dateFormat = SimpleDateFormat("HH:mm", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转分秒 - */ - fun millsToTime(millSeconds: Long): String { - dateFormat = SimpleDateFormat("mm:ss", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/WebCrawler.kt b/app/src/main/java/com/casic/qd/smartwell/utils/WebCrawler.kt new file mode 100644 index 0000000..94172f5 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/utils/WebCrawler.kt @@ -0,0 +1,92 @@ +package com.casic.qd.smartwell.utils + +import androidx.lifecycle.LifecycleCoroutineScope +import com.casic.qd.smartwell.model.BannerImageModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.jsoup.Jsoup +import org.jsoup.helper.HttpConnection +import java.io.IOException + +/** + * 网络爬虫 + * */ +class WebCrawler private constructor(builder: Builder) { + + private val lifecycleScope: LifecycleCoroutineScope = builder.lifecycleScope + private val ignore: Boolean = builder.ignore + private val time: Int = builder.time + private val url: String = builder.url + private val callback: OnWebCrawlerCallback = builder.callback + + class Builder { + lateinit var lifecycleScope: LifecycleCoroutineScope + var ignore: Boolean = true + var time: Int = 30 * 1000 + lateinit var url: String + lateinit var callback: OnWebCrawlerCallback + + fun addLifecycleCoroutineScope(lifecycleScope: LifecycleCoroutineScope): Builder { + this.lifecycleScope = lifecycleScope + return this + } + + fun ignoreHttpErrors(ignore: Boolean): Builder { + this.ignore = ignore + return this + } + + fun setTimeout(time: Int): Builder { + this.time = time + return this + } + + fun setTargetWebSite(url: String): Builder { + this.url = url + return this + } + + fun addOnWebCrawlerCallback(callback: OnWebCrawlerCallback): Builder { + this.callback = callback + return this + } + + fun build(): WebCrawler { + return WebCrawler(this) + } + } + + interface OnWebCrawlerCallback { + fun onParseSuccess(model: BannerImageModel) + + fun onParseFailure(e: Exception) + } + + //开始爬取数据 + fun start() { + val connection = Jsoup + .connect(url).userAgent(HttpConnection.DEFAULT_UA) + .timeout(time).ignoreHttpErrors(ignore) + lifecycleScope.launch(Dispatchers.Main) { + val statusCode = withContext(Dispatchers.IO) { + connection.execute().statusCode() + } + if (statusCode == 200) { + val document = withContext(Dispatchers.IO) { + connection.get() + } + val bannerModel = BannerImageModel() + val title = document.select("td[class]").first()?.text() + bannerModel.imageTitle = title + val image = document.select("p").select("a[href]")[1].attr("href") + bannerModel.imageLink = Constant.BASE_URL + image + bannerModel.webPageLink = url + + callback.onParseSuccess(bannerModel) + } else { + callback.onParseFailure(IOException()) + } + } + } +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index b3a6cfc..d06afef 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -49,6 +49,7 @@ implementation 'com.gyf.immersionbar:immersionbar:3.0.0' //MVVM+LiveData implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 @@ -82,4 +83,6 @@ implementation 'com.just.agentweb:agentweb-androidx:4.1.4' //日期选择器 implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' + //Html解析,爬虫 + implementation 'org.jsoup:jsoup:1.14.3' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt b/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt index d6af0f1..62d6a11 100644 --- a/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt +++ b/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt @@ -9,22 +9,11 @@ */ class BannerImageModel { /** - * success : true - * code : 200 - * message : 请求成功 - * data : [{"imageTitle":"测试标题1","imageLink":"https://images.pexels.com/photos/1036808/pexels-photo-1036808.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题2","imageLink":"https://images.pexels.com/photos/796602/pexels-photo-796602.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题3","imageLink":"https://images.pexels.com/photos/1109543/pexels-photo-1109543.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题4","imageLink":"https://images.pexels.com/photos/296115/pexels-photo-296115.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题5","imageLink":"https://images.pexels.com/photos/4158/apple-iphone-smartphone-desk.jpg?auto=compress&cs=tinysrgb&dpr=1&w=500"}] + * imageTitle : 亚洲首例300级深水导管架“海基一号”成... + * imageLink : https://www.cnoocengineering.com/picture/0/9c577a461ef24aafb9b1e06b8387f0ce.jpg + * webPageLink : /art/2022/4/12/art_29351_15325995.html */ - var isSuccess = false - var code = 0 - var message: String? = null - var data: List? = null - - class DataBean { - /** - * imageTitle : 测试标题1 - * imageLink : https://images.pexels.com/photos/1036808/pexels-photo-1036808.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500 - */ - var imageTitle: String? = null - var imageLink: String? = null - } + var imageTitle: String? = null + var imageLink: String? = null + var webPageLink: String? = null } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt index cb85f80..da8d67c 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt @@ -34,4 +34,23 @@ const val USER_DEVICE_TYPE = "userDeviceType" const val CANCEL_ALARM_ACTION = "cancelAlarm" const val AREA_ID = "110000" + const val BANNER_MODEL = "bannerModel" + + //首页Banner图目的网址 + /** + * 公司网站 + * */ + const val BASE_URL = "https://www.cnoocengineering.com/" + + /** + * 公司大事记 + * */ + val NEWS_PAGE = + arrayOf( + BASE_URL + "art/2022/4/12/art_29351_15325995.html", + BASE_URL + "art/2022/3/23/art_29351_15325404.html", + BASE_URL + "art/2022/3/18/art_29351_15325302.html", + BASE_URL + "art/2022/3/4/art_29351_15324210.html", + BASE_URL + "art/2022/2/28/art_29351_15324078.html" + ) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/TimeOrDateUtil.kt b/app/src/main/java/com/casic/qd/smartwell/utils/TimeOrDateUtil.kt deleted file mode 100644 index 35ca1b0..0000000 --- a/app/src/main/java/com/casic/qd/smartwell/utils/TimeOrDateUtil.kt +++ /dev/null @@ -1,113 +0,0 @@ -package com.casic.qd.smartwell.utils - -import java.text.ParseException -import java.text.SimpleDateFormat -import java.util.* - -/** - * @author : Pengxh - * @time : 2021/4/15 16:54 - * @email : 290677893@qq.com - */ -object TimeOrDateUtil { - private var dateFormat: SimpleDateFormat? = null - - /** - * 获取年月区间,[2022-02-01,2022-02-28] - */ - @Throws(ParseException::class) - fun timestampToMonth(millSeconds: Long): Array { - dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA) - //先判断是否在当月 - return if (isInThisMonth(millSeconds)) { - val date = Date() - val calendar = Calendar.getInstance() - calendar.time = date - //获得本月第一天 - calendar.add(Calendar.MONTH, 0) - calendar[Calendar.DAY_OF_MONTH] = 1 - val firstDay = dateFormat!!.format(calendar.time) - date.time = millSeconds - val currentDay = dateFormat!!.format(date) - arrayOf(firstDay, currentDay) - } else { - val dateValue = dateFormat!!.format(Date(millSeconds)) - val date = dateFormat!!.parse(dateValue) - val calendar = Calendar.getInstance() - calendar.time = date - //获得月第一天 - calendar.add(Calendar.MONTH, 0) - calendar[Calendar.DAY_OF_MONTH] = 1 - val firstDay = dateFormat!!.format(calendar.time) - val year = calendar[Calendar.YEAR] - val m = calendar[Calendar.MONTH] + 1 - val month: String = if (m < 10) { - "0$m" - } else { - m.toString() - } - val maxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH) - arrayOf(firstDay, "$year-$month-$maxDay") - } - } - - /** - * 判断时间是否在本月之内 - */ - private fun isInThisMonth(millSeconds: Long): Boolean { - //所选时间对应的月份 - val dateFormat = SimpleDateFormat("MM", Locale.CHINA) - val selectedMonth = dateFormat.format(Date(millSeconds)) - //系统时间对应的月份 - val systemMonth = dateFormat.format(Date(System.currentTimeMillis())) - return selectedMonth == systemMonth - } - - /** - * 时间戳转年月日时分秒 - */ - fun timestampToCompleteDate(millSeconds: Long): String { - dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转年月日 - */ - fun timestampToDate(millSeconds: Long): String { - dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转年月 - */ - fun timestampToYearMonth(millSeconds: Long): String { - dateFormat = SimpleDateFormat("yyyy年MM月", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转时分秒 - */ - fun timestampToTime(millSeconds: Long): String { - dateFormat = SimpleDateFormat("HH:mm:ss", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转时分 - */ - fun minuteToTime(millSeconds: Long): String { - dateFormat = SimpleDateFormat("HH:mm", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转分秒 - */ - fun millsToTime(millSeconds: Long): String { - dateFormat = SimpleDateFormat("mm:ss", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/WebCrawler.kt b/app/src/main/java/com/casic/qd/smartwell/utils/WebCrawler.kt new file mode 100644 index 0000000..94172f5 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/utils/WebCrawler.kt @@ -0,0 +1,92 @@ +package com.casic.qd.smartwell.utils + +import androidx.lifecycle.LifecycleCoroutineScope +import com.casic.qd.smartwell.model.BannerImageModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.jsoup.Jsoup +import org.jsoup.helper.HttpConnection +import java.io.IOException + +/** + * 网络爬虫 + * */ +class WebCrawler private constructor(builder: Builder) { + + private val lifecycleScope: LifecycleCoroutineScope = builder.lifecycleScope + private val ignore: Boolean = builder.ignore + private val time: Int = builder.time + private val url: String = builder.url + private val callback: OnWebCrawlerCallback = builder.callback + + class Builder { + lateinit var lifecycleScope: LifecycleCoroutineScope + var ignore: Boolean = true + var time: Int = 30 * 1000 + lateinit var url: String + lateinit var callback: OnWebCrawlerCallback + + fun addLifecycleCoroutineScope(lifecycleScope: LifecycleCoroutineScope): Builder { + this.lifecycleScope = lifecycleScope + return this + } + + fun ignoreHttpErrors(ignore: Boolean): Builder { + this.ignore = ignore + return this + } + + fun setTimeout(time: Int): Builder { + this.time = time + return this + } + + fun setTargetWebSite(url: String): Builder { + this.url = url + return this + } + + fun addOnWebCrawlerCallback(callback: OnWebCrawlerCallback): Builder { + this.callback = callback + return this + } + + fun build(): WebCrawler { + return WebCrawler(this) + } + } + + interface OnWebCrawlerCallback { + fun onParseSuccess(model: BannerImageModel) + + fun onParseFailure(e: Exception) + } + + //开始爬取数据 + fun start() { + val connection = Jsoup + .connect(url).userAgent(HttpConnection.DEFAULT_UA) + .timeout(time).ignoreHttpErrors(ignore) + lifecycleScope.launch(Dispatchers.Main) { + val statusCode = withContext(Dispatchers.IO) { + connection.execute().statusCode() + } + if (statusCode == 200) { + val document = withContext(Dispatchers.IO) { + connection.get() + } + val bannerModel = BannerImageModel() + val title = document.select("td[class]").first()?.text() + bannerModel.imageTitle = title + val image = document.select("p").select("a[href]")[1].attr("href") + bannerModel.imageLink = Constant.BASE_URL + image + bannerModel.webPageLink = url + + callback.onParseSuccess(bannerModel) + } else { + callback.onParseFailure(IOException()) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 3f4bb3c..702d8d1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -4,12 +4,12 @@ import android.os.Handler import android.os.Looper import android.os.Message +import android.util.Log import android.view.KeyEvent import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import com.bumptech.glide.Glide -import com.bumptech.glide.load.resource.bitmap.RoundedCorners -import com.bumptech.glide.request.RequestOptions import com.casic.qd.smartwell.R import com.casic.qd.smartwell.adapter.HomeRecycleAdapter import com.casic.qd.smartwell.base.BaseActivity @@ -20,6 +20,8 @@ import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel import com.github.mikephil.charting.data.Entry +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog import com.pengxh.app.multilib.widget.dialog.BottomActionSheet import com.youth.banner.Banner @@ -33,33 +35,16 @@ class MainActivity : BaseActivity() { + private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() - private val imageUrls = listOf( - "https://images.pexels.com/photos/1036808/pexels-photo-1036808.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500", - "https://images.pexels.com/photos/796602/pexels-photo-796602.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500", - "https://images.pexels.com/photos/1109543/pexels-photo-1109543.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500", - "https://images.pexels.com/photos/296115/pexels-photo-296115.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500", - "https://images.pexels.com/photos/4158/apple-iphone-smartphone-desk.jpg?auto=compress&cs=tinysrgb&dpr=1&w=500" - ) + private var imageModels: MutableList = ArrayList() private lateinit var weakReferenceHandler: WeakReferenceHandler - //TODO 测试数据 - private fun getData(): MutableList { - val list = ArrayList() - for (i in 0..4) { - val dataBean: BannerImageModel.DataBean = BannerImageModel.DataBean() - dataBean.imageTitle = "测试图片$i" - dataBean.imageLink = imageUrls[i] - list.add(dataBean) - } - return list - } - override fun initLayoutView(): Int = R.layout.activity_main override fun setupTopBarLayout() { @@ -67,28 +52,46 @@ } override fun initData() { + val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJsonModel.isNotBlank()) { + imageModels = Gson().fromJson( + bannerJsonModel, object : TypeToken>() {}.type + ) + } else { + Constant.NEWS_PAGE.forEach { + WebCrawler.Builder() + .addLifecycleCoroutineScope(lifecycleScope) + .ignoreHttpErrors(true) + .setTimeout(15000) + .setTargetWebSite(it) + .addOnWebCrawlerCallback(object : WebCrawler.OnWebCrawlerCallback { + override fun onParseSuccess(model: BannerImageModel) { + imageModels.add(model) + } + + override fun onParseFailure(e: Exception) { + Log.e(kTag, "onParseFailure: $e", e) + } + }).build().start() + } + } //轮播图 val banner = - (mainBannerView as Banner>) + (mainBannerView as Banner>) banner.apply { addBannerLifecycleObserver(this@MainActivity) indicator = CircleIndicator(context) - setAdapter(object : BannerImageAdapter(getData()) { + setBannerRound(15f) + setAdapter(object : BannerImageAdapter(imageModels) { override fun onBindView( - holder: BannerImageHolder, - data: BannerImageModel.DataBean, - position: Int, - size: Int + holder: BannerImageHolder, data: BannerImageModel, position: Int, size: Int ) { - Glide.with(holder.itemView) - .load(data.imageLink) - .apply(RequestOptions.bitmapTransform(RoundedCorners(30))) - .into(holder.imageView) + Glide.with(holder.itemView).load(data.imageLink).into(holder.imageView) } }) //Banner点击事件 - setOnBannerListener { data, _ -> - navigatePageTo(WebsiteActivity::class.java) + setOnBannerListener { imageModel, _ -> + navigatePageTo(WebsiteActivity::class.java, imageModel.webPageLink!!) } } diff --git a/app/build.gradle b/app/build.gradle index b3a6cfc..d06afef 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -49,6 +49,7 @@ implementation 'com.gyf.immersionbar:immersionbar:3.0.0' //MVVM+LiveData implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1" + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" //Kotlin协程 @@ -82,4 +83,6 @@ implementation 'com.just.agentweb:agentweb-androidx:4.1.4' //日期选择器 implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' + //Html解析,爬虫 + implementation 'org.jsoup:jsoup:1.14.3' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt b/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt index d6af0f1..62d6a11 100644 --- a/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt +++ b/app/src/main/java/com/casic/qd/smartwell/model/BannerImageModel.kt @@ -9,22 +9,11 @@ */ class BannerImageModel { /** - * success : true - * code : 200 - * message : 请求成功 - * data : [{"imageTitle":"测试标题1","imageLink":"https://images.pexels.com/photos/1036808/pexels-photo-1036808.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题2","imageLink":"https://images.pexels.com/photos/796602/pexels-photo-796602.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题3","imageLink":"https://images.pexels.com/photos/1109543/pexels-photo-1109543.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题4","imageLink":"https://images.pexels.com/photos/296115/pexels-photo-296115.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"},{"imageTitle":"测试标题5","imageLink":"https://images.pexels.com/photos/4158/apple-iphone-smartphone-desk.jpg?auto=compress&cs=tinysrgb&dpr=1&w=500"}] + * imageTitle : 亚洲首例300级深水导管架“海基一号”成... + * imageLink : https://www.cnoocengineering.com/picture/0/9c577a461ef24aafb9b1e06b8387f0ce.jpg + * webPageLink : /art/2022/4/12/art_29351_15325995.html */ - var isSuccess = false - var code = 0 - var message: String? = null - var data: List? = null - - class DataBean { - /** - * imageTitle : 测试标题1 - * imageLink : https://images.pexels.com/photos/1036808/pexels-photo-1036808.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500 - */ - var imageTitle: String? = null - var imageLink: String? = null - } + var imageTitle: String? = null + var imageLink: String? = null + var webPageLink: String? = null } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt index cb85f80..da8d67c 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt @@ -34,4 +34,23 @@ const val USER_DEVICE_TYPE = "userDeviceType" const val CANCEL_ALARM_ACTION = "cancelAlarm" const val AREA_ID = "110000" + const val BANNER_MODEL = "bannerModel" + + //首页Banner图目的网址 + /** + * 公司网站 + * */ + const val BASE_URL = "https://www.cnoocengineering.com/" + + /** + * 公司大事记 + * */ + val NEWS_PAGE = + arrayOf( + BASE_URL + "art/2022/4/12/art_29351_15325995.html", + BASE_URL + "art/2022/3/23/art_29351_15325404.html", + BASE_URL + "art/2022/3/18/art_29351_15325302.html", + BASE_URL + "art/2022/3/4/art_29351_15324210.html", + BASE_URL + "art/2022/2/28/art_29351_15324078.html" + ) } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/TimeOrDateUtil.kt b/app/src/main/java/com/casic/qd/smartwell/utils/TimeOrDateUtil.kt deleted file mode 100644 index 35ca1b0..0000000 --- a/app/src/main/java/com/casic/qd/smartwell/utils/TimeOrDateUtil.kt +++ /dev/null @@ -1,113 +0,0 @@ -package com.casic.qd.smartwell.utils - -import java.text.ParseException -import java.text.SimpleDateFormat -import java.util.* - -/** - * @author : Pengxh - * @time : 2021/4/15 16:54 - * @email : 290677893@qq.com - */ -object TimeOrDateUtil { - private var dateFormat: SimpleDateFormat? = null - - /** - * 获取年月区间,[2022-02-01,2022-02-28] - */ - @Throws(ParseException::class) - fun timestampToMonth(millSeconds: Long): Array { - dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA) - //先判断是否在当月 - return if (isInThisMonth(millSeconds)) { - val date = Date() - val calendar = Calendar.getInstance() - calendar.time = date - //获得本月第一天 - calendar.add(Calendar.MONTH, 0) - calendar[Calendar.DAY_OF_MONTH] = 1 - val firstDay = dateFormat!!.format(calendar.time) - date.time = millSeconds - val currentDay = dateFormat!!.format(date) - arrayOf(firstDay, currentDay) - } else { - val dateValue = dateFormat!!.format(Date(millSeconds)) - val date = dateFormat!!.parse(dateValue) - val calendar = Calendar.getInstance() - calendar.time = date - //获得月第一天 - calendar.add(Calendar.MONTH, 0) - calendar[Calendar.DAY_OF_MONTH] = 1 - val firstDay = dateFormat!!.format(calendar.time) - val year = calendar[Calendar.YEAR] - val m = calendar[Calendar.MONTH] + 1 - val month: String = if (m < 10) { - "0$m" - } else { - m.toString() - } - val maxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH) - arrayOf(firstDay, "$year-$month-$maxDay") - } - } - - /** - * 判断时间是否在本月之内 - */ - private fun isInThisMonth(millSeconds: Long): Boolean { - //所选时间对应的月份 - val dateFormat = SimpleDateFormat("MM", Locale.CHINA) - val selectedMonth = dateFormat.format(Date(millSeconds)) - //系统时间对应的月份 - val systemMonth = dateFormat.format(Date(System.currentTimeMillis())) - return selectedMonth == systemMonth - } - - /** - * 时间戳转年月日时分秒 - */ - fun timestampToCompleteDate(millSeconds: Long): String { - dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转年月日 - */ - fun timestampToDate(millSeconds: Long): String { - dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转年月 - */ - fun timestampToYearMonth(millSeconds: Long): String { - dateFormat = SimpleDateFormat("yyyy年MM月", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转时分秒 - */ - fun timestampToTime(millSeconds: Long): String { - dateFormat = SimpleDateFormat("HH:mm:ss", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转时分 - */ - fun minuteToTime(millSeconds: Long): String { - dateFormat = SimpleDateFormat("HH:mm", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } - - /** - * 时间戳转分秒 - */ - fun millsToTime(millSeconds: Long): String { - dateFormat = SimpleDateFormat("mm:ss", Locale.CHINA) - return dateFormat!!.format(Date(millSeconds)) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/WebCrawler.kt b/app/src/main/java/com/casic/qd/smartwell/utils/WebCrawler.kt new file mode 100644 index 0000000..94172f5 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/utils/WebCrawler.kt @@ -0,0 +1,92 @@ +package com.casic.qd.smartwell.utils + +import androidx.lifecycle.LifecycleCoroutineScope +import com.casic.qd.smartwell.model.BannerImageModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.jsoup.Jsoup +import org.jsoup.helper.HttpConnection +import java.io.IOException + +/** + * 网络爬虫 + * */ +class WebCrawler private constructor(builder: Builder) { + + private val lifecycleScope: LifecycleCoroutineScope = builder.lifecycleScope + private val ignore: Boolean = builder.ignore + private val time: Int = builder.time + private val url: String = builder.url + private val callback: OnWebCrawlerCallback = builder.callback + + class Builder { + lateinit var lifecycleScope: LifecycleCoroutineScope + var ignore: Boolean = true + var time: Int = 30 * 1000 + lateinit var url: String + lateinit var callback: OnWebCrawlerCallback + + fun addLifecycleCoroutineScope(lifecycleScope: LifecycleCoroutineScope): Builder { + this.lifecycleScope = lifecycleScope + return this + } + + fun ignoreHttpErrors(ignore: Boolean): Builder { + this.ignore = ignore + return this + } + + fun setTimeout(time: Int): Builder { + this.time = time + return this + } + + fun setTargetWebSite(url: String): Builder { + this.url = url + return this + } + + fun addOnWebCrawlerCallback(callback: OnWebCrawlerCallback): Builder { + this.callback = callback + return this + } + + fun build(): WebCrawler { + return WebCrawler(this) + } + } + + interface OnWebCrawlerCallback { + fun onParseSuccess(model: BannerImageModel) + + fun onParseFailure(e: Exception) + } + + //开始爬取数据 + fun start() { + val connection = Jsoup + .connect(url).userAgent(HttpConnection.DEFAULT_UA) + .timeout(time).ignoreHttpErrors(ignore) + lifecycleScope.launch(Dispatchers.Main) { + val statusCode = withContext(Dispatchers.IO) { + connection.execute().statusCode() + } + if (statusCode == 200) { + val document = withContext(Dispatchers.IO) { + connection.get() + } + val bannerModel = BannerImageModel() + val title = document.select("td[class]").first()?.text() + bannerModel.imageTitle = title + val image = document.select("p").select("a[href]")[1].attr("href") + bannerModel.imageLink = Constant.BASE_URL + image + bannerModel.webPageLink = url + + callback.onParseSuccess(bannerModel) + } else { + callback.onParseFailure(IOException()) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 3f4bb3c..702d8d1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -4,12 +4,12 @@ import android.os.Handler import android.os.Looper import android.os.Message +import android.util.Log import android.view.KeyEvent import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import com.bumptech.glide.Glide -import com.bumptech.glide.load.resource.bitmap.RoundedCorners -import com.bumptech.glide.request.RequestOptions import com.casic.qd.smartwell.R import com.casic.qd.smartwell.adapter.HomeRecycleAdapter import com.casic.qd.smartwell.base.BaseActivity @@ -20,6 +20,8 @@ import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel import com.github.mikephil.charting.data.Entry +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog import com.pengxh.app.multilib.widget.dialog.BottomActionSheet import com.youth.banner.Banner @@ -33,33 +35,16 @@ class MainActivity : BaseActivity() { + private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() - private val imageUrls = listOf( - "https://images.pexels.com/photos/1036808/pexels-photo-1036808.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500", - "https://images.pexels.com/photos/796602/pexels-photo-796602.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500", - "https://images.pexels.com/photos/1109543/pexels-photo-1109543.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500", - "https://images.pexels.com/photos/296115/pexels-photo-296115.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500", - "https://images.pexels.com/photos/4158/apple-iphone-smartphone-desk.jpg?auto=compress&cs=tinysrgb&dpr=1&w=500" - ) + private var imageModels: MutableList = ArrayList() private lateinit var weakReferenceHandler: WeakReferenceHandler - //TODO 测试数据 - private fun getData(): MutableList { - val list = ArrayList() - for (i in 0..4) { - val dataBean: BannerImageModel.DataBean = BannerImageModel.DataBean() - dataBean.imageTitle = "测试图片$i" - dataBean.imageLink = imageUrls[i] - list.add(dataBean) - } - return list - } - override fun initLayoutView(): Int = R.layout.activity_main override fun setupTopBarLayout() { @@ -67,28 +52,46 @@ } override fun initData() { + val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJsonModel.isNotBlank()) { + imageModels = Gson().fromJson( + bannerJsonModel, object : TypeToken>() {}.type + ) + } else { + Constant.NEWS_PAGE.forEach { + WebCrawler.Builder() + .addLifecycleCoroutineScope(lifecycleScope) + .ignoreHttpErrors(true) + .setTimeout(15000) + .setTargetWebSite(it) + .addOnWebCrawlerCallback(object : WebCrawler.OnWebCrawlerCallback { + override fun onParseSuccess(model: BannerImageModel) { + imageModels.add(model) + } + + override fun onParseFailure(e: Exception) { + Log.e(kTag, "onParseFailure: $e", e) + } + }).build().start() + } + } //轮播图 val banner = - (mainBannerView as Banner>) + (mainBannerView as Banner>) banner.apply { addBannerLifecycleObserver(this@MainActivity) indicator = CircleIndicator(context) - setAdapter(object : BannerImageAdapter(getData()) { + setBannerRound(15f) + setAdapter(object : BannerImageAdapter(imageModels) { override fun onBindView( - holder: BannerImageHolder, - data: BannerImageModel.DataBean, - position: Int, - size: Int + holder: BannerImageHolder, data: BannerImageModel, position: Int, size: Int ) { - Glide.with(holder.itemView) - .load(data.imageLink) - .apply(RequestOptions.bitmapTransform(RoundedCorners(30))) - .into(holder.imageView) + Glide.with(holder.itemView).load(data.imageLink).into(holder.imageView) } }) //Banner点击事件 - setOnBannerListener { data, _ -> - navigatePageTo(WebsiteActivity::class.java) + setOnBannerListener { imageModel, _ -> + navigatePageTo(WebsiteActivity::class.java, imageModel.webPageLink!!) } } diff --git a/app/src/main/java/com/casic/qd/smartwell/view/SplashScreenActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/SplashScreenActivity.kt index 7c050bb..d535868 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/SplashScreenActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/SplashScreenActivity.kt @@ -1,17 +1,26 @@ package com.casic.qd.smartwell.view import android.os.CountDownTimer +import android.util.Log import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import com.casic.qd.smartwell.R import com.casic.qd.smartwell.base.BaseActivity import com.casic.qd.smartwell.extensions.navigatePageTo +import com.casic.qd.smartwell.extensions.toJson +import com.casic.qd.smartwell.model.BannerImageModel +import com.casic.qd.smartwell.utils.Constant +import com.casic.qd.smartwell.utils.SaveKeyValues +import com.casic.qd.smartwell.utils.WebCrawler import com.casic.qd.smartwell.vm.AuthenticateViewModel import com.casic.qd.smartwell.vm.UserDetailViewModel class SplashScreenActivity : BaseActivity() { + private val kTag = "SplashScreenActivity" private lateinit var userDetailViewModel: UserDetailViewModel private lateinit var authenticateViewModel: AuthenticateViewModel + private val imageModels: MutableList = ArrayList() override fun initLayoutView(): Int = R.layout.activity_splash @@ -25,6 +34,23 @@ } override fun initEvent() { + Constant.NEWS_PAGE.forEach { + WebCrawler.Builder() + .addLifecycleCoroutineScope(lifecycleScope) + .ignoreHttpErrors(true) + .setTimeout(15000) + .setTargetWebSite(it) + .addOnWebCrawlerCallback(object : WebCrawler.OnWebCrawlerCallback { + override fun onParseSuccess(model: BannerImageModel) { + imageModels.add(model) + SaveKeyValues.putValue(Constant.BANNER_MODEL, imageModels.toJson()) + } + + override fun onParseFailure(e: Exception) { + Log.e(kTag, "onParseFailure: $e", e) + } + }).build().start() + } countDownTimer.start() }