refactor:Use viewModel
This commit is contained in:
@@ -11,6 +11,7 @@ import com.google.android.material.color.DynamicColors
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import com.lsp.view.service.DownloadService
|
import com.lsp.view.service.DownloadService
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import com.lsp.view.repository.PostRepository
|
||||||
|
|
||||||
class YandViewApplication : Application(), DefaultLifecycleObserver {
|
class YandViewApplication : Application(), DefaultLifecycleObserver {
|
||||||
private val connection: ServiceConnection = object : ServiceConnection {
|
private val connection: ServiceConnection = object : ServiceConnection {
|
||||||
@@ -20,6 +21,7 @@ class YandViewApplication : Application(), DefaultLifecycleObserver {
|
|||||||
|
|
||||||
override fun onServiceDisconnected(componentName: ComponentName) {}
|
override fun onServiceDisconnected(componentName: ComponentName) {}
|
||||||
}
|
}
|
||||||
|
val repository = PostRepository()
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super<Application>.onCreate()
|
super<Application>.onCreate()
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import com.lsp.view.YandViewApplication
|
|||||||
import com.lsp.view.R
|
import com.lsp.view.R
|
||||||
import com.lsp.view.activity.BaseActivity
|
import com.lsp.view.activity.BaseActivity
|
||||||
import com.lsp.view.activity.main.MainActivity
|
import com.lsp.view.activity.main.MainActivity
|
||||||
import com.lsp.view.bean.Tags
|
import com.lsp.view.repository.bean.Tags
|
||||||
|
|
||||||
class FavTagActivity : BaseActivity() {
|
class FavTagActivity : BaseActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import androidx.recyclerview.widget.RecyclerView
|
|||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
import com.lsp.view.R
|
import com.lsp.view.R
|
||||||
import com.lsp.view.bean.Tags
|
import com.lsp.view.repository.bean.Tags
|
||||||
|
|
||||||
class FavTagAdapter(val tagList: ArrayList<Tags>, val context: Context) :
|
class FavTagAdapter(val tagList: ArrayList<Tags>, val context: Context) :
|
||||||
RecyclerView.Adapter<FavTagAdapter.ViewHolder>() {
|
RecyclerView.Adapter<FavTagAdapter.ViewHolder>() {
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import android.animation.Animator
|
|||||||
import android.animation.AnimatorListenerAdapter
|
import android.animation.AnimatorListenerAdapter
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.*
|
import android.os.*
|
||||||
|
import android.util.Log
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.core.view.GravityCompat
|
import androidx.core.view.GravityCompat
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
@@ -18,100 +20,64 @@ import androidx.recyclerview.widget.RecyclerView
|
|||||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||||
import com.google.android.material.appbar.AppBarLayout
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
import com.google.android.material.navigation.NavigationView
|
import com.google.android.material.navigation.NavigationView
|
||||||
import com.google.android.material.snackbar.Snackbar
|
|
||||||
import com.lsp.view.YandViewApplication
|
import com.lsp.view.YandViewApplication
|
||||||
import com.lsp.view.R
|
import com.lsp.view.R
|
||||||
import com.lsp.view.activity.BaseActivity
|
import com.lsp.view.activity.BaseActivity
|
||||||
import com.lsp.view.activity.favtag.FavTagActivity
|
import com.lsp.view.activity.favtag.FavTagActivity
|
||||||
import com.lsp.view.activity.model.MainActivityModelImpl
|
|
||||||
import com.lsp.view.activity.setting.SettingsActivity
|
import com.lsp.view.activity.setting.SettingsActivity
|
||||||
import com.lsp.view.bean.YandPost
|
import com.lsp.view.model.MainViewModel
|
||||||
import com.lsp.view.util.CallBackStatus
|
|
||||||
|
|
||||||
|
|
||||||
class MainActivity : BaseActivity() {
|
class MainActivity : BaseActivity() {
|
||||||
private lateinit var search: EditText
|
private lateinit var search: EditText
|
||||||
private var shortAnnotationDuration: Int = 0
|
private var shortAnnotationDuration: Int = 0
|
||||||
private var nowPage = 1
|
|
||||||
private val adapter: PostAdapter = PostAdapter(this, ArrayList())
|
|
||||||
private var username: String? = ""
|
private var username: String? = ""
|
||||||
private lateinit var sourceUrlArray: Array<String>
|
|
||||||
private lateinit var sourceNameArray: Array<String>
|
|
||||||
private var nowSourceName: String? = null
|
private var nowSourceName: String? = null
|
||||||
val TAG = javaClass.simpleName
|
val TAG = javaClass.simpleName
|
||||||
private lateinit var layoutManager: RecyclerView.LayoutManager
|
|
||||||
private var safeMode: Boolean = true //安全模式
|
private var safeMode: Boolean = true //安全模式
|
||||||
private lateinit var recyclerView: RecyclerView
|
|
||||||
private var barShow = false
|
|
||||||
private var tags: String? = ""
|
|
||||||
private val ISREFRESH = 1
|
|
||||||
private val ISADDDATA = 0
|
|
||||||
private lateinit var toolbar:Toolbar
|
private lateinit var toolbar:Toolbar
|
||||||
|
private lateinit var viewModel: MainViewModel
|
||||||
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
|
viewModel = MainViewModel.provideFactory((application as YandViewApplication).repository, this,this).create(MainViewModel::class.java)
|
||||||
|
|
||||||
toolbar = findViewById(R.id.toolbar)
|
toolbar = findViewById(R.id.toolbar)
|
||||||
setSupportActionBar(toolbar)
|
setSupportActionBar(toolbar)
|
||||||
val appbar = findViewById<AppBarLayout>(R.id.appbar)
|
val appbar = findViewById<AppBarLayout>(R.id.appbar)
|
||||||
val nowHeight = appbar.layoutParams.height
|
val nowHeight = appbar.layoutParams.height
|
||||||
appbar.layoutParams.height = (application as YandViewApplication).statusBarHeight()+nowHeight
|
appbar.layoutParams.height = (application as YandViewApplication).statusBarHeight()+nowHeight
|
||||||
|
//刷新
|
||||||
|
val refresh =
|
||||||
|
findViewById<androidx.swiperefreshlayout.widget.SwipeRefreshLayout>(R.id.swipeRefreshLayout)
|
||||||
|
|
||||||
//到达底部,加载更多数据
|
viewModel.uiState.value.isRefreshing.observe(this) {
|
||||||
adapter.setLoadMoreListener(object : PostAdapter.OnLoadMoreListener {
|
refresh.isRefreshing = it
|
||||||
//重写接口
|
|
||||||
override fun loadMore(position: Int) {
|
|
||||||
loadData(tags,++nowPage,ISADDDATA)
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
//初始化数据
|
|
||||||
sourceNameArray = resources.getStringArray(R.array.pic_source)
|
|
||||||
sourceUrlArray = resources.getStringArray(R.array.url_source)
|
|
||||||
val configSp = getSharedPreferences("com.lsp.view_preferences", 0)
|
|
||||||
if (configSp.getString("source_name", null) == null) {
|
|
||||||
configSp.edit().putString("source_name", "yande.re").apply()
|
|
||||||
configSp.edit().putString("type", "0").apply()
|
|
||||||
}
|
}
|
||||||
nowSourceName = configSp.getString("source_name","yande.re")
|
|
||||||
safeMode = configSp.getBoolean("safe_mode",true)
|
|
||||||
|
|
||||||
|
refresh.setOnRefreshListener {
|
||||||
|
viewModel.fetchPostByRefresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.adapter.apply {
|
||||||
|
setLoadMoreListener(object :PostAdapter.OnScrollToBottom{
|
||||||
|
override fun event(position: Int) {
|
||||||
|
viewModel.appendPost()
|
||||||
|
}
|
||||||
|
|
||||||
//横屏逻辑
|
})
|
||||||
layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
|
}
|
||||||
recyclerView = findViewById(R.id.recyclerview)
|
|
||||||
|
|
||||||
recyclerView.layoutManager = layoutManager
|
|
||||||
recyclerView.adapter = adapter
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//收藏Tag
|
|
||||||
val swipeRefreshLayout =
|
|
||||||
findViewById<androidx.swiperefreshlayout.widget.SwipeRefreshLayout>(
|
|
||||||
R.id.swipeRefreshLayout
|
|
||||||
)
|
|
||||||
val drawerLayout = findViewById<DrawerLayout>(R.id.drawerLayout)
|
|
||||||
|
|
||||||
|
findViewById<RecyclerView>(R.id.recyclerview).apply {
|
||||||
|
val layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
|
||||||
|
this.layoutManager = layoutManager
|
||||||
|
this.adapter = viewModel.adapter
|
||||||
|
}
|
||||||
|
|
||||||
search = findViewById(R.id.search)
|
search = findViewById(R.id.search)
|
||||||
//快捷搜索tag 来自PicActivity
|
|
||||||
val searchTag = intent.getStringExtra("searchTag")
|
|
||||||
if (searchTag != null) {
|
|
||||||
//tag按钮搜索
|
|
||||||
this.search.setText(searchTag)
|
|
||||||
action(searchTag)
|
|
||||||
} else {
|
|
||||||
//初次启动
|
|
||||||
action("")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
supportActionBar?.let {
|
supportActionBar?.let {
|
||||||
it.setDisplayHomeAsUpEnabled(true)
|
it.setDisplayHomeAsUpEnabled(true)
|
||||||
@@ -122,17 +88,12 @@ class MainActivity : BaseActivity() {
|
|||||||
|
|
||||||
search.setOnEditorActionListener { _, actionId, _ ->
|
search.setOnEditorActionListener { _, actionId, _ ->
|
||||||
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
||||||
action(search.text.toString())
|
viewModel.fetchNewPostBySearch(search.text.toString())
|
||||||
}
|
}
|
||||||
return@setOnEditorActionListener false
|
return@setOnEditorActionListener false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//刷新
|
|
||||||
swipeRefreshLayout.setOnRefreshListener {
|
|
||||||
nowPage = 1
|
|
||||||
loadData(tags, nowPage, ISREFRESH)
|
|
||||||
}
|
|
||||||
|
|
||||||
//侧边栏
|
//侧边栏
|
||||||
val sp = getSharedPreferences("username", 0)
|
val sp = getSharedPreferences("username", 0)
|
||||||
@@ -144,10 +105,11 @@ class MainActivity : BaseActivity() {
|
|||||||
nav.setCheckedItem(R.id.photo)
|
nav.setCheckedItem(R.id.photo)
|
||||||
//设置侧边栏点击逻辑
|
//设置侧边栏点击逻辑
|
||||||
nav.setNavigationItemSelectedListener {
|
nav.setNavigationItemSelectedListener {
|
||||||
|
val drawerLayout = findViewById<DrawerLayout>(R.id.drawerLayout)
|
||||||
when (it.itemId) {
|
when (it.itemId) {
|
||||||
//画廊
|
//画廊
|
||||||
R.id.photo -> {
|
R.id.photo -> {
|
||||||
loadData( null, 1, ISREFRESH)
|
viewModel.fetchPostByRefresh()
|
||||||
drawerLayout.closeDrawers()
|
drawerLayout.closeDrawers()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -174,15 +136,16 @@ class MainActivity : BaseActivity() {
|
|||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
//加载源改变
|
//加载源改变
|
||||||
val configSp = getSharedPreferences("com.lsp.view_preferences", 0)
|
val configSp = getSharedPreferences("com.lsp.view_preferences", 0)
|
||||||
if (nowSourceName != configSp.getString("source_name",null)){
|
if (nowSourceName != configSp.getString("source_name",null)){
|
||||||
action("")
|
viewModel.fetchPostByRefresh()
|
||||||
nowSourceName = configSp.getString("source_name",null)
|
nowSourceName = configSp.getString("source_name",null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (safeMode != configSp.getBoolean("safe_mode",true)){
|
if (safeMode != configSp.getBoolean("safe_mode",true)){
|
||||||
action("")
|
viewModel.fetchPostByRefresh()
|
||||||
safeMode = configSp.getBoolean("safe_mode",true)
|
safeMode = configSp.getBoolean("safe_mode",true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,8 +165,7 @@ class MainActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
hideIm()
|
hideIm()
|
||||||
barShow = false
|
viewModel.uiState.value.switchShowSearchBar()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//现实搜索栏
|
//现实搜索栏
|
||||||
@@ -217,13 +179,13 @@ class MainActivity : BaseActivity() {
|
|||||||
.setDuration(shortAnnotationDuration.toLong())
|
.setDuration(shortAnnotationDuration.toLong())
|
||||||
.setListener(null)
|
.setListener(null)
|
||||||
}
|
}
|
||||||
barShow = true
|
viewModel.uiState.value.switchShowSearchBar()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
android.R.id.home -> {
|
android.R.id.home -> {
|
||||||
if (barShow){
|
if (viewModel.uiState.value.showSearchBar){
|
||||||
hiddenSearchBar()
|
hiddenSearchBar()
|
||||||
}else {
|
}else {
|
||||||
val drawerLayout = findViewById<DrawerLayout>(R.id.drawerLayout)
|
val drawerLayout = findViewById<DrawerLayout>(R.id.drawerLayout)
|
||||||
@@ -231,8 +193,8 @@ class MainActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
R.id.search_nav -> {
|
R.id.search_nav -> {
|
||||||
if (barShow) {
|
if (viewModel.uiState.value.showSearchBar) {
|
||||||
action(search.text.toString())
|
viewModel.fetchNewPostBySearch(search.text.toString())
|
||||||
hideIm()
|
hideIm()
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -250,78 +212,6 @@ class MainActivity : BaseActivity() {
|
|||||||
WindowCompat.getInsetsController(this.window,window.decorView).hide(ime())
|
WindowCompat.getInsetsController(this.window,window.decorView).hide(ime())
|
||||||
}
|
}
|
||||||
|
|
||||||
//执行加载
|
|
||||||
private fun action(searchTag :String?) {
|
|
||||||
var tag = searchTag
|
|
||||||
var isNum = true
|
|
||||||
try {
|
|
||||||
tag?.toInt()
|
|
||||||
}catch (e:NumberFormatException){
|
|
||||||
isNum = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNum){
|
|
||||||
tag = "id:"+searchTag
|
|
||||||
}
|
|
||||||
|
|
||||||
loadData(tag, 1, ISREFRESH)
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//设置列表数据
|
|
||||||
private fun loadData(tags: String?,page: Int,type:Int){
|
|
||||||
//缓存搜索的tags
|
|
||||||
this.tags = tags
|
|
||||||
|
|
||||||
val swipeRefreshLayout =
|
|
||||||
findViewById<androidx.swiperefreshlayout.widget.SwipeRefreshLayout>(
|
|
||||||
R.id.swipeRefreshLayout
|
|
||||||
)
|
|
||||||
swipeRefreshLayout.isRefreshing = true
|
|
||||||
|
|
||||||
//读取配置
|
|
||||||
val configSp = getSharedPreferences("com.lsp.view_preferences", 0)
|
|
||||||
val nowSourceName: String? = configSp.getString("source_name",null)
|
|
||||||
var source = ""
|
|
||||||
for ((index,sourceName) in sourceNameArray.withIndex()){
|
|
||||||
if (sourceName == nowSourceName){
|
|
||||||
source = sourceUrlArray[index]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//接收异步信息
|
|
||||||
val handler = object : Handler(Looper.myLooper()!!){
|
|
||||||
override fun handleMessage(msg: Message) {
|
|
||||||
super.handleMessage(msg)
|
|
||||||
when (msg.what){
|
|
||||||
CallBackStatus.DATAISNULL.ordinal ->{
|
|
||||||
Snackbar.make(swipeRefreshLayout,R.string.toast_load_empty,Snackbar.LENGTH_SHORT).show()
|
|
||||||
search.setText("")
|
|
||||||
}
|
|
||||||
CallBackStatus.OK.ordinal -> {
|
|
||||||
if (type == ISREFRESH )
|
|
||||||
//刷新数据
|
|
||||||
adapter.refreshData(msg.obj as ArrayList<YandPost>)
|
|
||||||
else if (type == ISADDDATA)
|
|
||||||
//加载数据
|
|
||||||
adapter.addData(msg.obj as ArrayList<YandPost>)
|
|
||||||
|
|
||||||
}
|
|
||||||
CallBackStatus.NETWORKERROR.ordinal -> {
|
|
||||||
Snackbar.make(swipeRefreshLayout,R.string.toast_load_network_fail,Snackbar.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
swipeRefreshLayout.isRefreshing = false
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MainActivityModelImpl().requestPostList(handler,source,tags,page,configSp.getBoolean("safe_mode",true))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||||
menuInflater.inflate(R.menu.toolbar_menu, menu)
|
menuInflater.inflate(R.menu.toolbar_menu, menu)
|
||||||
|
|||||||
@@ -1,91 +1,105 @@
|
|||||||
package com.lsp.view.activity.main
|
package com.lsp.view.activity.main
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.os.Message
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.load.model.GlideUrl
|
import com.bumptech.glide.load.model.GlideUrl
|
||||||
import com.bumptech.glide.load.model.LazyHeaders
|
import com.bumptech.glide.load.model.LazyHeaders
|
||||||
import com.lsp.view.R
|
import com.lsp.view.R
|
||||||
import com.lsp.view.activity.pic.PicActivity
|
import com.lsp.view.activity.pic.PicActivity
|
||||||
import com.lsp.view.bean.YandPost
|
import com.lsp.view.repository.bean.YandPost
|
||||||
|
|
||||||
|
|
||||||
class PostAdapter(val context: Context, private var postYandList: ArrayList<YandPost>) :
|
class PostAdapter(val context: Context):
|
||||||
RecyclerView.Adapter<PostAdapter.ViewHolder>() {
|
RecyclerView.Adapter<PostAdapter.ViewHolder>() {
|
||||||
val TAG = this::class.java.simpleName
|
val TAG = this::class.java.simpleName
|
||||||
private val UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"
|
private val UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"
|
||||||
|
|
||||||
|
private var postList = ArrayList<YandPost>()
|
||||||
|
|
||||||
|
|
||||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
val picImage: ImageView = view.findViewById(R.id.picImgae)
|
val picImage: ImageView = view.findViewById(R.id.picImgae)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addData(list: ArrayList<YandPost>) {
|
fun pushNewData(list: ArrayList<YandPost>) {
|
||||||
val pos = postYandList.size
|
val oldSize = postList.size
|
||||||
postYandList.addAll(list)
|
postList.clear()
|
||||||
notifyItemRangeInserted(pos, list.size)
|
notifyItemRangeRemoved(0,oldSize)
|
||||||
|
postList.addAll(list)
|
||||||
|
notifyItemRangeInserted(0, list.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refreshData(list: ArrayList<YandPost>) {
|
fun appendDate(list: ArrayList<YandPost>){
|
||||||
|
val pos = postList.size
|
||||||
val oldSize = postYandList.size
|
postList.addAll(list)
|
||||||
postYandList.clear()
|
notifyItemRangeInserted(pos, list.size)
|
||||||
notifyItemRangeRemoved(0,oldSize)
|
|
||||||
postYandList.addAll(list)
|
|
||||||
notifyItemRangeInserted(0, list.size)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
val view = LayoutInflater.from(context).inflate(R.layout.img_item_layout, parent, false)
|
val view = LayoutInflater.from(context).inflate(R.layout.img_item_layout, parent, false)
|
||||||
val viewHolder = ViewHolder(view)
|
val viewHolder = ViewHolder(view)
|
||||||
|
|
||||||
viewHolder.picImage.setOnClickListener {
|
viewHolder.picImage.setOnClickListener {
|
||||||
val position = viewHolder.adapterPosition
|
val position = viewHolder.adapterPosition
|
||||||
Log.w("position", position.toString())
|
// Log.w("position", position.toString())
|
||||||
Log.w("url", postYandList[position].sample_url)
|
// Log.w("url", postList.value?.get(position)?.sample_url)
|
||||||
Log.w("rating", postYandList[position].rating)
|
// Log.w("rating", postList[position].rating)
|
||||||
var file_ext = postYandList[position].file_ext
|
var file_ext = postList[position].file_ext
|
||||||
|
|
||||||
if (file_ext == null){
|
if (file_ext == null){
|
||||||
val strarr = postYandList[position].sample_url.split(".")
|
val strarr = postList[position].sample_url.split(".")
|
||||||
file_ext = strarr[strarr.lastIndex]
|
file_ext = strarr[strarr.lastIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
PicActivity.actionStartActivity(context,postYandList[position].id,postYandList[position].sample_url,
|
PicActivity.actionStartActivity(
|
||||||
postYandList[position].file_url,postYandList[position].tags,file_ext,postYandList[position].file_size,postYandList[position].md5,postYandList[position].sample_height,postYandList[position].sample_width)
|
context,
|
||||||
|
postList[position].id,
|
||||||
|
postList[position].sample_url,
|
||||||
|
postList[position].file_url,
|
||||||
|
postList[position].tags,
|
||||||
|
file_ext,
|
||||||
|
postList[position].file_size,
|
||||||
|
postList[position].md5,
|
||||||
|
postList[position].sample_height,
|
||||||
|
postList[position].sample_width)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return viewHolder
|
return viewHolder
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var mLoadMoreListener: OnLoadMoreListener
|
private lateinit var mScrollToBottom: OnScrollToBottom
|
||||||
|
|
||||||
interface OnLoadMoreListener {
|
interface OnScrollToBottom {
|
||||||
fun loadMore(position: Int)
|
fun event(position: Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setLoadMoreListener(mLoadMoreListener: OnLoadMoreListener) {
|
fun setLoadMoreListener(mLoadMoreListener: OnScrollToBottom) {
|
||||||
this.mLoadMoreListener = mLoadMoreListener
|
this.mScrollToBottom = mLoadMoreListener
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun preLoad(p:Int){
|
private fun preLoad(p:Int){
|
||||||
if (p%20==0){
|
if (p%20==0){
|
||||||
//执行预加载
|
//执行预加载
|
||||||
val last:Int = if (postYandList.size-p<20){
|
val last:Int = if (postList.size-p<20){
|
||||||
postYandList.size-1
|
postList.size-1
|
||||||
}else{
|
}else{
|
||||||
p+19
|
p+19
|
||||||
}
|
}
|
||||||
for(index in p..last){
|
for(index in p..last){
|
||||||
if (p>6) {
|
if (p>6) {
|
||||||
val source: String = postYandList[index].sample_url
|
val source: String = postList[index].sample_url
|
||||||
val glideUrl = GlideUrl(
|
val glideUrl = GlideUrl(
|
||||||
source,
|
source,
|
||||||
LazyHeaders.Builder().addHeader("User-Agent", UA)
|
LazyHeaders.Builder().addHeader("User-Agent", UA)
|
||||||
@@ -95,18 +109,19 @@ class PostAdapter(val context: Context, private var postYandList: ArrayList<Yand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
|
||||||
preLoad(position)
|
preLoad(position)
|
||||||
|
|
||||||
val post = postYandList[position]
|
val post = postList[position]
|
||||||
|
|
||||||
val source: String = post.sample_url
|
val source: String = post.sample_url
|
||||||
|
|
||||||
val height = postYandList[position].sample_height
|
val height = postList[position].sample_height
|
||||||
val width = postYandList[position].sample_width
|
val width = postList[position].sample_width
|
||||||
|
|
||||||
//图片过长则缩减高度以保证显示完整
|
//图片过长则缩减高度以保证显示完整
|
||||||
if (width > height){
|
if (width > height){
|
||||||
@@ -123,15 +138,17 @@ class PostAdapter(val context: Context, private var postYandList: ArrayList<Yand
|
|||||||
)
|
)
|
||||||
Glide.with(context).load(glideUrl).into(holder.picImage)
|
Glide.with(context).load(glideUrl).into(holder.picImage)
|
||||||
|
|
||||||
if (position == postYandList.size - 1 && postYandList.size > 6) {
|
if (position == postList.size - 1 && postList.size > 6) {
|
||||||
//到达底部
|
//到达底部
|
||||||
mLoadMoreListener.loadMore(position)
|
mScrollToBottom.event(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
return postYandList.size
|
val size = postList.size
|
||||||
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
package com.lsp.view.activity.model
|
|
||||||
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Message
|
|
||||||
import com.lsp.view.bean.Post
|
|
||||||
import com.lsp.view.util.CallBackStatus
|
|
||||||
import retrofit2.Call
|
|
||||||
import retrofit2.Callback
|
|
||||||
import retrofit2.Response
|
|
||||||
|
|
||||||
open class BaseModel {
|
|
||||||
/**
|
|
||||||
* @param service ArrayList接收边界为Post的泛型,若直接使用Post作为泛型参数,需要强制类型转换。
|
|
||||||
*/
|
|
||||||
fun <T : Post> request(service: Call<ArrayList<T>>, safeMode: Boolean, handler: Handler){
|
|
||||||
|
|
||||||
service.enqueue(object : Callback<ArrayList<T>> {
|
|
||||||
override fun onResponse(call: Call<ArrayList<T>>, response: Response<ArrayList<T>>) {
|
|
||||||
val getValue:ArrayList<T>? = response.body()
|
|
||||||
|
|
||||||
if (getValue!=null) {
|
|
||||||
if (getValue.size==0){
|
|
||||||
callBack(handler, CallBackStatus.DATAISNULL)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (safeMode) {
|
|
||||||
val iter = getValue.iterator()
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
val post = iter.next()
|
|
||||||
if (post.rating != "s")
|
|
||||||
iter.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
callBack(handler, CallBackStatus.OK,getValue)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(call: Call<ArrayList<T>>, t: Throwable) {
|
|
||||||
callBack(handler, CallBackStatus.NETWORKERROR)
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T:Post> callBack(handler: Handler,status: CallBackStatus,value:ArrayList<T>){
|
|
||||||
val msg = Message.obtain()
|
|
||||||
msg.what = status.ordinal
|
|
||||||
msg.obj = value
|
|
||||||
handler.sendMessage(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun callBack(handler: Handler,status: CallBackStatus){
|
|
||||||
val msg = Message.obtain()
|
|
||||||
msg.what = status.ordinal
|
|
||||||
handler.sendMessage(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package com.lsp.view.activity.model
|
|
||||||
|
|
||||||
import android.os.Handler
|
|
||||||
|
|
||||||
interface MainActivityModel {
|
|
||||||
fun requestPostList(handler: Handler, source: String, tage: String?, page: Int, safeMode: Boolean)
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package com.lsp.view.activity.model
|
|
||||||
|
|
||||||
import android.os.Handler
|
|
||||||
import com.lsp.view.retrofit.PostService
|
|
||||||
import com.lsp.view.retrofit.ServiceCreator
|
|
||||||
import com.lsp.view.bean.YandPost
|
|
||||||
import retrofit2.Call
|
|
||||||
import kotlin.collections.ArrayList
|
|
||||||
|
|
||||||
class MainActivityModelImpl :MainActivityModel, BaseModel() {
|
|
||||||
private val TAG = this::class.java.simpleName
|
|
||||||
override fun requestPostList(handler: Handler, source: String, tage: String?, page: Int,safeMode: Boolean){
|
|
||||||
val postService: PostService = ServiceCreator.create(source)
|
|
||||||
val service: Call<ArrayList<YandPost>> = postService.getPostData("100",tage, page)
|
|
||||||
request(service,safeMode, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -10,8 +10,8 @@ import com.google.android.material.snackbar.Snackbar
|
|||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
import com.lsp.view.R
|
import com.lsp.view.R
|
||||||
import com.lsp.view.bean.ID
|
import com.lsp.view.repository.bean.ID
|
||||||
import com.lsp.view.bean.Tags
|
import com.lsp.view.repository.bean.Tags
|
||||||
|
|
||||||
class IdAdapter(val idList: List<ID>,val context: Context) : RecyclerView.Adapter<IdAdapter.ViewHolder>() {
|
class IdAdapter(val idList: List<ID>,val context: Context) : RecyclerView.Adapter<IdAdapter.ViewHolder>() {
|
||||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ import com.google.android.material.snackbar.Snackbar
|
|||||||
import com.lsp.view.R
|
import com.lsp.view.R
|
||||||
import com.lsp.view.activity.BaseActivity
|
import com.lsp.view.activity.BaseActivity
|
||||||
import com.lsp.view.activity.main.MainActivity
|
import com.lsp.view.activity.main.MainActivity
|
||||||
import com.lsp.view.bean.ID
|
import com.lsp.view.repository.bean.ID
|
||||||
import com.lsp.view.bean.Size
|
import com.lsp.view.repository.bean.Size
|
||||||
import com.lsp.view.bean.Tags
|
import com.lsp.view.repository.bean.Tags
|
||||||
import com.lsp.view.util.Util
|
import com.lsp.view.util.Util
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import android.view.ViewGroup
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.lsp.view.R
|
import com.lsp.view.R
|
||||||
import com.lsp.view.bean.Size
|
import com.lsp.view.repository.bean.Size
|
||||||
import java.math.RoundingMode
|
import java.math.RoundingMode
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import com.google.android.material.snackbar.Snackbar
|
|||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
import com.lsp.view.R
|
import com.lsp.view.R
|
||||||
import com.lsp.view.bean.Tags
|
import com.lsp.view.repository.bean.Tags
|
||||||
|
|
||||||
class TagAdapter(val tagList: List<Tags>, val context: Context) :
|
class TagAdapter(val tagList: List<Tags>, val context: Context) :
|
||||||
RecyclerView.Adapter<TagAdapter.ViewHolder>() {
|
RecyclerView.Adapter<TagAdapter.ViewHolder>() {
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
package com.lsp.view.bean
|
|
||||||
|
|
||||||
class Author(val author: String)
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
package com.lsp.view.bean
|
|
||||||
|
|
||||||
class ID(val id: String)
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
package com.lsp.view.bean
|
|
||||||
|
|
||||||
class Size(val file_size: String)
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
package com.lsp.view.bean
|
|
||||||
|
|
||||||
class Tags(val tag: String)
|
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package com.lsp.view.model
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Message
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.lifecycle.AbstractSavedStateViewModelFactory
|
||||||
|
import androidx.lifecycle.SavedStateHandle
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.lsp.view.activity.main.PostAdapter
|
||||||
|
import com.lsp.view.repository.PostRepository
|
||||||
|
import androidx.savedstate.SavedStateRegistryOwner
|
||||||
|
import com.lsp.view.repository.bean.YandPost
|
||||||
|
import com.lsp.view.repository.exception.NetworkErrorException
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class MainViewModel(private val repository: PostRepository,private val context: Context):ViewModel() {
|
||||||
|
private val _uiState = MutableStateFlow(UiState())
|
||||||
|
val uiState:StateFlow<UiState> = _uiState.asStateFlow()
|
||||||
|
private var fetchJob: Job? = null
|
||||||
|
val adapter = PostAdapter(context)
|
||||||
|
private val TAG = this::class.java.simpleName
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun provideFactory(
|
||||||
|
repository: PostRepository,
|
||||||
|
context: Context,
|
||||||
|
owner: SavedStateRegistryOwner,
|
||||||
|
defaultArgs: Bundle? = null,
|
||||||
|
|
||||||
|
): AbstractSavedStateViewModelFactory =
|
||||||
|
object : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T : ViewModel> create(
|
||||||
|
key: String,
|
||||||
|
modelClass: Class<T>,
|
||||||
|
handle: SavedStateHandle
|
||||||
|
): T {
|
||||||
|
return MainViewModel(repository, context) as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
//初始化写入
|
||||||
|
val configSp = context.getSharedPreferences("com.lsp.view_preferences", 0)
|
||||||
|
if (configSp.getString("source_name", null) == null) {
|
||||||
|
configSp.edit().putString("source_name", "yande.re").apply()
|
||||||
|
configSp.edit().putString("type", "0").apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(nowSourceName = configSp.getString("source_name",null))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fetchNewPost(){
|
||||||
|
fetchJob?.cancel()
|
||||||
|
fetchJob = viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
|
||||||
|
_uiState.value.isRefreshing.postValue(true)
|
||||||
|
|
||||||
|
try {
|
||||||
|
val postList = repository.fetchPostData(
|
||||||
|
_uiState.value.nowSearchText,
|
||||||
|
_uiState.value.isSafe,
|
||||||
|
_uiState.value.nowPage
|
||||||
|
)
|
||||||
|
|
||||||
|
launch(Dispatchers.Main) {
|
||||||
|
if (_uiState.value.isAppend){
|
||||||
|
adapter.appendDate(postList)
|
||||||
|
}else{
|
||||||
|
adapter.pushNewData(postList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}catch (e:NetworkErrorException){
|
||||||
|
launch(Dispatchers.Main){
|
||||||
|
Toast.makeText(context,e.message,Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_uiState.value.isRefreshing.postValue(false)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fetchNewPostBySearch(target:String){
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(nowSearchText = target)
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchNewPost()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fetchPostByRefresh(){
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(nowPage = 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchNewPost()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun appendPost(){
|
||||||
|
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(isAppend = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchNewPost()
|
||||||
|
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(isAppend = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.lsp.view.model
|
||||||
|
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
|
||||||
|
data class UiState(
|
||||||
|
var showSearchBar:Boolean = false,
|
||||||
|
val isRefreshing:MutableLiveData<Boolean> = MutableLiveData(),
|
||||||
|
val nowSearchText:String = "",
|
||||||
|
val nowSourceName: String? = null,
|
||||||
|
val isSafe: Boolean = true, //安全模式
|
||||||
|
val nowPage:Int = 1,
|
||||||
|
val isAppend:Boolean = false
|
||||||
|
){
|
||||||
|
fun switchShowSearchBar(){
|
||||||
|
showSearchBar = !showSearchBar
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.lsp.view.repository
|
||||||
|
|
||||||
|
import com.lsp.view.R
|
||||||
|
import com.lsp.view.YandViewApplication
|
||||||
|
import com.lsp.view.repository.exception.UnableConstructObjectException
|
||||||
|
import com.lsp.view.repository.api.PostApi
|
||||||
|
import com.lsp.view.repository.api.PostApiImpl
|
||||||
|
import com.lsp.view.repository.bean.YandPost
|
||||||
|
|
||||||
|
class PostDataSource {
|
||||||
|
private val api: PostApi = PostApiImpl()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//设置列表数据
|
||||||
|
suspend fun fetchNewPost(load: Load): ArrayList<YandPost> {
|
||||||
|
return api.fetchNewPost(load)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data class Load(
|
||||||
|
val tags: String?,
|
||||||
|
val page: Int,
|
||||||
|
val safe:Boolean
|
||||||
|
){
|
||||||
|
lateinit var source:String
|
||||||
|
|
||||||
|
companion object{
|
||||||
|
fun Builder(tags: String?, page: Int, safe:Boolean):Load{
|
||||||
|
val sourceNameArray = YandViewApplication.context!!.resources.getStringArray(R.array.pic_source)
|
||||||
|
val sourceUrlArray = YandViewApplication.context!!.resources.getStringArray(R.array.url_source)
|
||||||
|
val configSp = YandViewApplication.context?.getSharedPreferences("com.lsp.view_preferences", 0)
|
||||||
|
val nowSourceName: String? = configSp?.getString("source_name",null)
|
||||||
|
val load = Load(tags,page,safe)
|
||||||
|
|
||||||
|
//初始化数据
|
||||||
|
for ((index,sourceName) in sourceNameArray.withIndex()){
|
||||||
|
if (sourceName == nowSourceName){
|
||||||
|
load.source = sourceUrlArray[index]
|
||||||
|
return load
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw UnableConstructObjectException("Unable construct load object.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.lsp.view.repository
|
||||||
|
|
||||||
|
import android.os.Handler
|
||||||
|
import com.lsp.view.repository.bean.YandPost
|
||||||
|
|
||||||
|
|
||||||
|
class PostRepository {
|
||||||
|
private val dataSource = PostDataSource()
|
||||||
|
|
||||||
|
//获取post
|
||||||
|
suspend fun fetchPostData(searchTarget :String?,safe:Boolean,page:Int): ArrayList<YandPost> {
|
||||||
|
|
||||||
|
var target = searchTarget
|
||||||
|
var isNum = true
|
||||||
|
|
||||||
|
//如果检索目标是纯数字,则按照id搜索
|
||||||
|
try {
|
||||||
|
target?.toLong()
|
||||||
|
}catch (e:NumberFormatException){
|
||||||
|
isNum = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNum){
|
||||||
|
target = "id:$searchTarget"
|
||||||
|
}
|
||||||
|
|
||||||
|
val load = Load.Builder(target,page,safe)
|
||||||
|
|
||||||
|
return dataSource.fetchNewPost(load)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.lsp.view.repository.api
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import com.lsp.view.repository.Load
|
||||||
|
import com.lsp.view.repository.bean.Post
|
||||||
|
import com.lsp.view.repository.bean.YandPost
|
||||||
|
import com.lsp.view.repository.exception.NetworkErrorException
|
||||||
|
import retrofit2.Call
|
||||||
|
import java.net.SocketException
|
||||||
|
|
||||||
|
interface PostApi {
|
||||||
|
private val TAG: String
|
||||||
|
get() = this::class.java.simpleName
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param service ArrayList接收边界为Post的泛型,若直接使用Post作为泛型参数,需要强制类型转换。
|
||||||
|
*/
|
||||||
|
@Throws(NetworkErrorException::class)
|
||||||
|
fun <T : Post> request(service: Call<ArrayList<T>>, safeMode: Boolean):ArrayList<T> {
|
||||||
|
|
||||||
|
try {
|
||||||
|
val execute = service.execute()
|
||||||
|
return if (execute.isSuccessful) {
|
||||||
|
if (execute.body() != null) {
|
||||||
|
Log.e(TAG, execute.body().toString())
|
||||||
|
execute.body()!!
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//结果为空,返回空集避免空指针
|
||||||
|
ArrayList()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw NetworkErrorException(execute.errorBody().toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
}catch (e: Exception){
|
||||||
|
throw NetworkErrorException(e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun fetchNewPost(load:Load):ArrayList<YandPost>
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.lsp.view.repository.api
|
||||||
|
|
||||||
|
import com.lsp.view.repository.Load
|
||||||
|
import com.lsp.view.retrofit.PostService
|
||||||
|
import com.lsp.view.retrofit.ServiceCreator
|
||||||
|
import com.lsp.view.repository.bean.YandPost
|
||||||
|
import retrofit2.Call
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
class PostApiImpl :PostApi {
|
||||||
|
private val TAG = this::class.java.simpleName
|
||||||
|
private val defaultLimit = "100"
|
||||||
|
override suspend fun fetchNewPost(load: Load):ArrayList<YandPost>{
|
||||||
|
val postService: PostService = ServiceCreator.create(load.source)
|
||||||
|
val service: Call<ArrayList<YandPost>> = postService.getPostData(defaultLimit,load.tags, load.page)
|
||||||
|
|
||||||
|
return request(service, load.safe)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package com.lsp.view.repository.bean
|
||||||
|
|
||||||
|
class Author(val author: String)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package com.lsp.view.repository.bean
|
||||||
|
|
||||||
|
class ID(val id: String)
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.lsp.view.bean
|
package com.lsp.view.repository.bean
|
||||||
|
|
||||||
open class Post(
|
open class Post(
|
||||||
val id: String,
|
val id: String,
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package com.lsp.view.repository.bean
|
||||||
|
|
||||||
|
class Size(val file_size: String)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package com.lsp.view.repository.bean
|
||||||
|
|
||||||
|
class Tags(val tag: String)
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.lsp.view.bean
|
package com.lsp.view.repository.bean
|
||||||
|
|
||||||
class YandPost(
|
class YandPost(
|
||||||
val preview_url: String,
|
val preview_url: String,
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.lsp.view.repository.exception
|
||||||
|
|
||||||
|
import okhttp3.ResponseBody
|
||||||
|
|
||||||
|
class NetworkErrorException(override val message: String?) : Exception() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.lsp.view.repository.exception
|
||||||
|
|
||||||
|
import java.lang.Exception
|
||||||
|
|
||||||
|
class UnableConstructObjectException(override val message: String?):Exception(message) {
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.lsp.view.retrofit
|
package com.lsp.view.retrofit
|
||||||
|
|
||||||
import com.lsp.view.bean.YandPost
|
import com.lsp.view.repository.bean.YandPost
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
|
|||||||
@@ -11,13 +11,11 @@ object ServiceCreator {
|
|||||||
* @param source:加载根地址
|
* @param source:加载根地址
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
var source: String? = null
|
|
||||||
fun <T> create(serviceClass: Class<T>, source: String): T {
|
fun <T> create(serviceClass: Class<T>, source: String): T {
|
||||||
val retrofit = Retrofit.Builder()
|
val retrofit = Retrofit.Builder()
|
||||||
.baseUrl(source)
|
.baseUrl(source)
|
||||||
.addConverterFactory(GsonConverterFactory.create())
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
.build()
|
.build()
|
||||||
ServiceCreator.source = source
|
|
||||||
return retrofit.create(serviceClass)
|
return retrofit.create(serviceClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.media.MediaScannerConnection
|
import android.media.MediaScannerConnection
|
||||||
import android.os.*
|
import android.os.*
|
||||||
import com.lsp.view.util.CallBackStatus
|
import com.lsp.view.util.Util
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -19,7 +19,7 @@ class DownloadService : Service() {
|
|||||||
|
|
||||||
class DownloadBinder(val context: Context) : Binder() {
|
class DownloadBinder(val context: Context) : Binder() {
|
||||||
|
|
||||||
fun callBack(handler: Handler,status:CallBackStatus){
|
fun callBack(handler: Handler,status:Int){
|
||||||
val msg = Message.obtain()
|
val msg = Message.obtain()
|
||||||
msg.obj = status
|
msg.obj = status
|
||||||
handler.sendMessage(msg)
|
handler.sendMessage(msg)
|
||||||
@@ -35,7 +35,7 @@ class DownloadService : Service() {
|
|||||||
File("${Environment.getExternalStorageDirectory()}/${Environment.DIRECTORY_PICTURES}/LspMake/$md5.$end")
|
File("${Environment.getExternalStorageDirectory()}/${Environment.DIRECTORY_PICTURES}/LspMake/$md5.$end")
|
||||||
|
|
||||||
if (file.exists()){
|
if (file.exists()){
|
||||||
callBack(handler,CallBackStatus.FILEEXISTS)
|
callBack(handler,Util.FILE_EXISTS)
|
||||||
return@thread
|
return@thread
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,24 +57,24 @@ class DownloadService : Service() {
|
|||||||
null, null
|
null, null
|
||||||
)
|
)
|
||||||
if (md5 == getFileMD5(file.path)) {
|
if (md5 == getFileMD5(file.path)) {
|
||||||
callBack(handler, CallBackStatus.DOWNLOADSUCCESS)
|
callBack(handler, Util.DOWNLOAD_SUCCESS)
|
||||||
} else {
|
} else {
|
||||||
file.delete()
|
file.delete()
|
||||||
callBack(handler,CallBackStatus.MD5COMPAREERROR)
|
callBack(handler,Util.MD5_COMPARE_ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
return@thread
|
return@thread
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
file.delete()
|
file.delete()
|
||||||
callBack(handler, CallBackStatus.NETWORKERROR)
|
callBack(handler, Util.NETWORK_ERROR)
|
||||||
return@thread
|
return@thread
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
callBack(handler, CallBackStatus.DOWNLOADERROR)
|
callBack(handler, Util.DOWNLOAD_ERROR)
|
||||||
return@thread
|
return@thread
|
||||||
} finally {
|
} finally {
|
||||||
fos.close()
|
fos.close()
|
||||||
@@ -84,7 +84,7 @@ class DownloadService : Service() {
|
|||||||
FileD.mkdirs()
|
FileD.mkdirs()
|
||||||
downloadPic(file_url, end, handler, md5)
|
downloadPic(file_url, end, handler, md5)
|
||||||
}
|
}
|
||||||
callBack(handler,CallBackStatus.DOWNLOADERROR)
|
callBack(handler,Util.DOWNLOAD_ERROR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
package com.lsp.view.util
|
|
||||||
|
|
||||||
enum class CallBackStatus {
|
|
||||||
OK, NETWORKERROR, DATAISNULL, DOWNLOADERROR, SETWP, MD5COMPAREERROR, FILEEXISTS, DOWNLOADSUCCESS
|
|
||||||
}
|
|
||||||
@@ -18,6 +18,12 @@ import java.io.File
|
|||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
object Util {
|
object Util {
|
||||||
|
const val NETWORK_ERROR: Int = 0
|
||||||
|
const val DOWNLOAD_SUCCESS = 1
|
||||||
|
const val DOWNLOAD_ERROR = 2
|
||||||
|
const val MD5_COMPARE_ERROR = 3
|
||||||
|
const val FILE_EXISTS = 4
|
||||||
|
|
||||||
fun share(url:String,context: Context){
|
fun share(url:String,context: Context){
|
||||||
thread {
|
thread {
|
||||||
val bitmap = Glide.with(context).asBitmap().load(url).submit().get()
|
val bitmap = Glide.with(context).asBitmap().load(url).submit().get()
|
||||||
@@ -83,19 +89,19 @@ object Util {
|
|||||||
override fun handleMessage(msg: Message) {
|
override fun handleMessage(msg: Message) {
|
||||||
super.handleMessage(msg)
|
super.handleMessage(msg)
|
||||||
when(msg.obj){
|
when(msg.obj){
|
||||||
CallBackStatus.DOWNLOADSUCCESS ->{
|
DOWNLOAD_SUCCESS ->{
|
||||||
Toast.makeText(YandViewApplication.context, R.string.toast_download_success, Toast.LENGTH_SHORT).show()
|
Toast.makeText(YandViewApplication.context, R.string.toast_download_success, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
CallBackStatus.DOWNLOADERROR.ordinal -> {
|
DOWNLOAD_ERROR -> {
|
||||||
Toast.makeText(YandViewApplication.context, R.string.toast_download_fail, Toast.LENGTH_SHORT).show()
|
Toast.makeText(YandViewApplication.context, R.string.toast_download_fail, Toast.LENGTH_SHORT).show()
|
||||||
|
|
||||||
}
|
}
|
||||||
CallBackStatus.MD5COMPAREERROR.ordinal -> {
|
MD5_COMPARE_ERROR -> {
|
||||||
Toast.makeText(YandViewApplication.context, R.string.toast_compar_md5_fail, Toast.LENGTH_SHORT).show()
|
Toast.makeText(YandViewApplication.context, R.string.toast_compar_md5_fail, Toast.LENGTH_SHORT).show()
|
||||||
|
|
||||||
}
|
}
|
||||||
CallBackStatus.FILEEXISTS.ordinal -> {
|
FILE_EXISTS -> {
|
||||||
Toast.makeText(YandViewApplication.context, R.string.toast_file_exist, Toast.LENGTH_SHORT).show()
|
Toast.makeText(YandViewApplication.context, R.string.toast_file_exist, Toast.LENGTH_SHORT).show()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user