refactor: To material3
This commit is contained in:
+15
-2
@@ -1,6 +1,9 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'com.android.application'
|
id 'com.android.application'
|
||||||
id 'kotlin-android'
|
id 'kotlin-android'
|
||||||
|
id 'androidx.navigation.safeargs.kotlin'
|
||||||
|
id "com.google.devtools.ksp"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@@ -33,9 +36,17 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
def room_version = "2.5.0"
|
||||||
|
|
||||||
|
implementation "androidx.room:room-runtime:$room_version"
|
||||||
|
implementation "androidx.room:room-ktx:$room_version"
|
||||||
|
annotationProcessor "androidx.room:room-compiler:$room_version"
|
||||||
|
ksp "androidx.room:room-compiler:$room_version"
|
||||||
|
|
||||||
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2"
|
||||||
|
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"
|
||||||
implementation("com.google.android.material:material:1.10.0")
|
implementation("com.google.android.material:material:1.10.0")
|
||||||
implementation 'jp.wasabeef:recyclerview-animators:4.0.2'
|
implementation 'jp.wasabeef:recyclerview-animators:4.0.2'
|
||||||
implementation "androidx.drawerlayout:drawerlayout:1.1.1"
|
|
||||||
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
||||||
implementation 'com.google.android.flexbox:flexbox:3.0.0'
|
implementation 'com.google.android.flexbox:flexbox:3.0.0'
|
||||||
implementation ('androidx.swiperefreshlayout:swiperefreshlayout:1.1.0')
|
implementation ('androidx.swiperefreshlayout:swiperefreshlayout:1.1.0')
|
||||||
@@ -43,8 +54,10 @@ dependencies {
|
|||||||
implementation ('com.squareup.retrofit2:converter-gson:2.9.0')
|
implementation ('com.squareup.retrofit2:converter-gson:2.9.0')
|
||||||
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
||||||
implementation 'androidx.preference:preference-ktx:1.2.0'
|
implementation 'androidx.preference:preference-ktx:1.2.0'
|
||||||
|
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.5'
|
||||||
|
implementation "androidx.navigation:navigation-ui-ktx:2.7.5"
|
||||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
|
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.0"
|
||||||
implementation 'androidx.core:core-ktx:1.9.0'
|
implementation 'androidx.core:core-ktx:1.9.0'
|
||||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
||||||
|
|||||||
@@ -23,12 +23,8 @@
|
|||||||
android:resource="@xml/file_paths">
|
android:resource="@xml/file_paths">
|
||||||
</meta-data>
|
</meta-data>
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".activity.favtag.FavTagActivity"
|
android:name=".activity.SettingsActivity"
|
||||||
android:exported="false" />
|
|
||||||
<activity
|
|
||||||
android:name=".activity.setting.SettingsActivity"
|
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:label="@string/title_activity_settings" />
|
android:label="@string/title_activity_settings" />
|
||||||
|
|
||||||
@@ -36,12 +32,8 @@
|
|||||||
android:name=".service.DownloadService"
|
android:name=".service.DownloadService"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="true" />
|
android:exported="true" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".activity.pic.PicActivity"
|
android:name=".activity.MainActivity"
|
||||||
android:configChanges="uiMode"/>
|
|
||||||
<activity
|
|
||||||
android:name=".activity.main.MainActivity"
|
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ import android.os.IBinder
|
|||||||
import com.lsp.view.service.DownloadService.DownloadBinder
|
import com.lsp.view.service.DownloadService.DownloadBinder
|
||||||
import com.google.android.material.color.DynamicColors
|
import com.google.android.material.color.DynamicColors
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.util.Log
|
||||||
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 {
|
||||||
|
lateinit var downloadBinder:DownloadBinder
|
||||||
|
|
||||||
private val connection: ServiceConnection = object : ServiceConnection {
|
private val connection: ServiceConnection = object : ServiceConnection {
|
||||||
override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) {
|
override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) {
|
||||||
downloadBinder = iBinder as DownloadBinder
|
downloadBinder = iBinder as DownloadBinder
|
||||||
@@ -21,14 +23,14 @@ 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()
|
||||||
context = applicationContext
|
context = applicationContext
|
||||||
DynamicColors.applyToActivitiesIfAvailable(this)
|
|
||||||
val serviceIntent = Intent(this, DownloadService::class.java)
|
val serviceIntent = Intent(this, DownloadService::class.java)
|
||||||
bindService(serviceIntent, connection, BIND_AUTO_CREATE)
|
bindService(serviceIntent, connection, BIND_AUTO_CREATE)
|
||||||
|
|
||||||
|
DynamicColors.applyToActivitiesIfAvailable(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy(owner: LifecycleOwner) {
|
override fun onDestroy(owner: LifecycleOwner) {
|
||||||
@@ -39,7 +41,7 @@ class YandViewApplication : Application(), DefaultLifecycleObserver {
|
|||||||
companion object {
|
companion object {
|
||||||
var context: Context? = null
|
var context: Context? = null
|
||||||
private set
|
private set
|
||||||
var downloadBinder: DownloadBinder? = null
|
const 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 set
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package com.lsp.view.activity
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
|
import androidx.navigation.ui.setupWithNavController
|
||||||
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
|
import com.lsp.view.R
|
||||||
|
import com.lsp.view.model.MainViewModel
|
||||||
|
import com.lsp.view.repository.network.PostRepository
|
||||||
|
|
||||||
|
|
||||||
|
class MainActivity : AppCompatActivity() {
|
||||||
|
val TAG = javaClass.simpleName
|
||||||
|
lateinit var viewModel: MainViewModel
|
||||||
|
lateinit var bottomNav:BottomNavigationView
|
||||||
|
val repository = PostRepository()
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
|
viewModel = MainViewModel.provideFactory(repository, this,this).create(MainViewModel::class.java)
|
||||||
|
|
||||||
|
bottomNav = findViewById(R.id.bottom_navigation)
|
||||||
|
|
||||||
|
viewModel.toastMessage.observe(this){
|
||||||
|
Toast.makeText(this,it,Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
//接收来自PicActivity的快捷搜索Tag
|
||||||
|
val stringExtra = intent.getStringExtra("searchTag")
|
||||||
|
if (stringExtra!=null){
|
||||||
|
viewModel.uiState.value.nowSearchText.value = stringExtra
|
||||||
|
}
|
||||||
|
|
||||||
|
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
|
||||||
|
val navController = navHostFragment.navController
|
||||||
|
bottomNav.setupWithNavController(navController)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
//加载源改变
|
||||||
|
val configSp = getSharedPreferences("com.lsp.view_preferences", 0)
|
||||||
|
|
||||||
|
val nowSourceName = configSp.getString("source_name", null)
|
||||||
|
|
||||||
|
if (nowSourceName != null && viewModel.uiState.value.nowSourceName.value != nowSourceName){
|
||||||
|
viewModel.updateNowSource(nowSourceName)
|
||||||
|
}
|
||||||
|
|
||||||
|
val nowMode = configSp.getBoolean("safe_mode", true)
|
||||||
|
if (viewModel.uiState.value.isSafe != nowMode){
|
||||||
|
viewModel.updateSafeMode(nowMode)
|
||||||
|
Log.e(TAG,nowMode.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.lsp.view.activity.setting
|
package com.lsp.view.activity
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package com.lsp.view.activity.favtag
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.MenuItem
|
|
||||||
import android.view.View
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.google.android.flexbox.*
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.reflect.TypeToken
|
|
||||||
import com.lsp.view.R
|
|
||||||
import com.lsp.view.activity.main.MainActivity
|
|
||||||
import com.lsp.view.repository.bean.Tags
|
|
||||||
|
|
||||||
class FavTagActivity : AppCompatActivity() {
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
setContentView(R.layout.activity_fav_tag)
|
|
||||||
|
|
||||||
|
|
||||||
//Toolbar相关
|
|
||||||
val toolbar = findViewById<Toolbar>(R.id.toolbar)
|
|
||||||
setSupportActionBar(toolbar)
|
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
|
||||||
supportActionBar?.setHomeButtonEnabled(true)
|
|
||||||
|
|
||||||
val recyclerViewTag = findViewById<RecyclerView>(R.id.tag_recy)
|
|
||||||
recyclerViewTag.layoutManager = layoutManager()
|
|
||||||
val tagsArraySp = getSharedPreferences("tags_sp", Context.MODE_PRIVATE)
|
|
||||||
val array = tagsArraySp.getString("array", null)
|
|
||||||
var favTagList: ArrayList<Tags> = ArrayList()
|
|
||||||
if (array != null) {
|
|
||||||
//有收藏内容
|
|
||||||
val tagListType = object : TypeToken<ArrayList<Tags>>() {}.type
|
|
||||||
favTagList = Gson().fromJson(array, tagListType)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
val favTagAdapter = FavTagAdapter(favTagList, this)
|
|
||||||
favTagAdapter.setOnItemClickListener(object : FavTagAdapter.OnItemClickListener {
|
|
||||||
override fun onItemClick(view: View, position: Int) {
|
|
||||||
val intent = Intent(this@FavTagActivity, MainActivity::class.java)
|
|
||||||
intent.putExtra("searchTag", favTagList[position].tag)
|
|
||||||
startActivity(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
recyclerViewTag.adapter = favTagAdapter
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun layoutManager(): FlexboxLayoutManager {
|
|
||||||
val manager = object : FlexboxLayoutManager(this, FlexDirection.ROW, FlexWrap.WRAP) {
|
|
||||||
override fun canScrollVertically(): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
manager.flexWrap = FlexWrap.WRAP
|
|
||||||
manager.flexDirection = FlexDirection.ROW
|
|
||||||
manager.alignItems = AlignItems.CENTER
|
|
||||||
manager.justifyContent = JustifyContent.FLEX_START
|
|
||||||
return manager
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
|
||||||
when (item.itemId) {
|
|
||||||
android.R.id.home -> {
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.onOptionsItemSelected(item)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
package com.lsp.view.activity.favtag
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.reflect.TypeToken
|
|
||||||
import com.lsp.view.R
|
|
||||||
import com.lsp.view.repository.bean.Tags
|
|
||||||
|
|
||||||
class FavTagAdapter(val tagList: ArrayList<Tags>, val context: Context) :
|
|
||||||
RecyclerView.Adapter<FavTagAdapter.ViewHolder>() {
|
|
||||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
|
||||||
val fav_tag = view.findViewById<TextView>(R.id.fav_tag)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var mOnItemClickListener: OnItemClickListener
|
|
||||||
|
|
||||||
interface OnItemClickListener {
|
|
||||||
fun onItemClick(view: View, position: Int)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setOnItemClickListener(mOnItemClickListener: OnItemClickListener) {
|
|
||||||
this.mOnItemClickListener = mOnItemClickListener
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
|
||||||
val view =
|
|
||||||
LayoutInflater.from(parent.context).inflate(R.layout.fav_tag_item_layout, parent, false)
|
|
||||||
val viewHolder = ViewHolder(view)
|
|
||||||
viewHolder.fav_tag.setOnLongClickListener {
|
|
||||||
val position = viewHolder.adapterPosition
|
|
||||||
removeData(position)
|
|
||||||
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
return viewHolder
|
|
||||||
}
|
|
||||||
|
|
||||||
fun removeData(position: Int) {
|
|
||||||
tagList.removeAt(position)
|
|
||||||
notifyItemRangeInserted(0, tagList.size)
|
|
||||||
val tagsArraySp = context.getSharedPreferences("tags_sp", Context.MODE_PRIVATE)
|
|
||||||
val tagsArrayJson = tagsArraySp.getString("array", null)
|
|
||||||
val tagListType = object : TypeToken<ArrayList<Tags>>() {}.type
|
|
||||||
val tagArray: ArrayList<Tags> = Gson().fromJson(tagsArrayJson, tagListType)
|
|
||||||
tagArray.removeAt(position)
|
|
||||||
tagsArraySp.edit().putString("array", Gson().toJson(tagArray)).apply()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
|
||||||
val tag = tagList[position].tag
|
|
||||||
holder.fav_tag.text = tag
|
|
||||||
holder.fav_tag.setOnClickListener {
|
|
||||||
mOnItemClickListener.onItemClick(it, position)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
|
||||||
return tagList.size
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
package com.lsp.view.activity.main
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.inputmethod.EditorInfo
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
|
||||||
import com.google.android.material.search.SearchBar
|
|
||||||
import com.google.android.material.search.SearchView
|
|
||||||
import com.google.android.material.snackbar.Snackbar
|
|
||||||
import com.lsp.view.R
|
|
||||||
import com.lsp.view.YandViewApplication
|
|
||||||
import com.lsp.view.model.MainViewModel
|
|
||||||
|
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
|
||||||
private var shortAnnotationDuration: Int = 0
|
|
||||||
private var username: String? = ""
|
|
||||||
val TAG = javaClass.simpleName
|
|
||||||
private lateinit var viewModel: MainViewModel
|
|
||||||
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
setContentView(R.layout.activity_main)
|
|
||||||
viewModel = MainViewModel.provideFactory((application as YandViewApplication).repository, this,this).create(MainViewModel::class.java)
|
|
||||||
|
|
||||||
val adapter by lazy {
|
|
||||||
viewModel.fetchPostByRefresh()
|
|
||||||
PostAdapter(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
//刷新
|
|
||||||
val refresh =
|
|
||||||
findViewById<androidx.swiperefreshlayout.widget.SwipeRefreshLayout>(R.id.swipeRefreshLayout)
|
|
||||||
|
|
||||||
viewModel.uiState.value.isRefreshing.observe(this) {
|
|
||||||
refresh.isRefreshing = it
|
|
||||||
}
|
|
||||||
viewModel.errorMessage.observe(this){
|
|
||||||
Snackbar.make(refresh,it,Snackbar.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
viewModel.postList.observe(this){
|
|
||||||
|
|
||||||
if (adapter.isAppendData){
|
|
||||||
adapter.appendDate(it)
|
|
||||||
}else{
|
|
||||||
adapter.pushNewData(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shortAnnotationDuration = resources.getInteger(android.R.integer.config_shortAnimTime)
|
|
||||||
val searchBar = findViewById<SearchBar>(R.id.search_bar)
|
|
||||||
val searchView = findViewById<SearchView>(R.id.search_view)
|
|
||||||
|
|
||||||
searchView.editText.setOnEditorActionListener { v, actionId, event ->
|
|
||||||
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
|
||||||
viewModel.fetchPostBySearch(searchView.text.toString())
|
|
||||||
searchBar.setText(searchView.text)
|
|
||||||
searchView.hide()
|
|
||||||
}
|
|
||||||
|
|
||||||
return@setOnEditorActionListener false
|
|
||||||
}
|
|
||||||
|
|
||||||
//接收来自PicActivity的快捷搜索Tag
|
|
||||||
val stringExtra = intent.getStringExtra("searchTag")
|
|
||||||
if (stringExtra!=null){
|
|
||||||
viewModel.uiState.value.nowSearchText.value = stringExtra
|
|
||||||
}
|
|
||||||
viewModel.uiState.value.nowSearchText.observe(this){
|
|
||||||
searchView.setText(it)
|
|
||||||
searchBar.setText(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
refresh.setOnRefreshListener {
|
|
||||||
viewModel.fetchPostByRefresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
adapter.apply {
|
|
||||||
setLoadMoreListener(object :PostAdapter.OnScrollToBottom{
|
|
||||||
override fun event(position: Int) {
|
|
||||||
adapter.isAppendData = true//设置数据状态为追加数据
|
|
||||||
viewModel.fetchMore()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
findViewById<RecyclerView>(R.id.recyclerview).apply {
|
|
||||||
val layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
|
|
||||||
this.layoutManager = layoutManager
|
|
||||||
this.adapter = adapter
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
supportActionBar?.let {
|
|
||||||
it.setDisplayHomeAsUpEnabled(true)
|
|
||||||
it.setHomeAsUpIndicator(R.drawable.ic_baseline_menu_24)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//侧边栏
|
|
||||||
val sp = getSharedPreferences("username", 0)
|
|
||||||
username = sp.getString("username", null)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
|
|
||||||
//加载源改变
|
|
||||||
val configSp = getSharedPreferences("com.lsp.view_preferences", 0)
|
|
||||||
|
|
||||||
val nowSourceName = configSp.getString("source_name", null)
|
|
||||||
|
|
||||||
if (nowSourceName != null && viewModel.uiState.value.nowSourceName.value != nowSourceName){
|
|
||||||
viewModel.updateNowSource(nowSourceName)
|
|
||||||
}
|
|
||||||
|
|
||||||
val nowMode = configSp.getBoolean("safe_mode", true)
|
|
||||||
if (viewModel.uiState.value.isSafe != nowMode){
|
|
||||||
viewModel.updateSafeMode(nowMode)
|
|
||||||
Log.e(TAG,nowMode.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
package com.lsp.view.activity.pic
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.google.android.material.snackbar.Snackbar
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.reflect.TypeToken
|
|
||||||
import com.lsp.view.R
|
|
||||||
import com.lsp.view.repository.bean.ID
|
|
||||||
import com.lsp.view.repository.bean.Tags
|
|
||||||
|
|
||||||
class IdAdapter(val idList: List<ID>,val context: Context) : RecyclerView.Adapter<IdAdapter.ViewHolder>() {
|
|
||||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
|
||||||
val tagText = view.findViewById<TextView>(R.id.tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
|
||||||
val view =
|
|
||||||
LayoutInflater.from(parent.context).inflate(R.layout.tag_item_layout, parent, false)
|
|
||||||
val viewHolder = ViewHolder(view)
|
|
||||||
viewHolder.tagText.setOnLongClickListener {
|
|
||||||
val position = viewHolder.adapterPosition
|
|
||||||
if (position == 0) {
|
|
||||||
//标题
|
|
||||||
return@setOnLongClickListener false
|
|
||||||
}
|
|
||||||
var tagsArray: ArrayList<Tags> = ArrayList()
|
|
||||||
val tagsArraySp = context.getSharedPreferences("tags_sp", Context.MODE_PRIVATE)
|
|
||||||
val tagsArrayJson = tagsArraySp.getString("array", null)
|
|
||||||
if (tagsArrayJson != null) {
|
|
||||||
val tagListType = object : TypeToken<ArrayList<Tags>>() {}.type
|
|
||||||
tagsArray = Gson().fromJson(tagsArrayJson, tagListType)
|
|
||||||
}
|
|
||||||
for (tag: Tags in tagsArray) {
|
|
||||||
if (tag.tag == viewHolder.tagText.text.toString()) {
|
|
||||||
Snackbar.make(viewHolder.tagText, "收藏过了哦", Snackbar.LENGTH_SHORT).show()
|
|
||||||
return@setOnLongClickListener true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tagsArray.add(Tags(viewHolder.tagText.text.toString()))
|
|
||||||
tagsArraySp.edit().putString("array", Gson().toJson(tagsArray)).apply()
|
|
||||||
Snackbar.make(viewHolder.tagText, "收藏了新标签", Snackbar.LENGTH_SHORT).show()
|
|
||||||
|
|
||||||
return@setOnLongClickListener true
|
|
||||||
}
|
|
||||||
return viewHolder
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
|
||||||
val tag = idList[position]
|
|
||||||
holder.tagText.text = tag.id
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
|
||||||
return idList.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,297 +0,0 @@
|
|||||||
package com.lsp.view.activity.pic
|
|
||||||
|
|
||||||
import android.animation.Animator
|
|
||||||
import android.animation.AnimatorListenerAdapter
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.os.*
|
|
||||||
import android.view.KeyEvent
|
|
||||||
import android.view.View
|
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import androidx.activity.addCallback
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import com.bumptech.glide.load.DataSource
|
|
||||||
import com.bumptech.glide.load.engine.GlideException
|
|
||||||
import com.bumptech.glide.load.model.GlideUrl
|
|
||||||
import com.bumptech.glide.load.model.LazyHeaders
|
|
||||||
import com.bumptech.glide.request.RequestListener
|
|
||||||
import com.bumptech.glide.request.target.Target
|
|
||||||
import com.github.chrisbanes.photoview.PhotoView
|
|
||||||
import com.google.android.flexbox.*
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
||||||
import com.google.android.material.snackbar.Snackbar
|
|
||||||
import com.lsp.view.R
|
|
||||||
import com.lsp.view.activity.main.MainActivity
|
|
||||||
import com.lsp.view.repository.bean.ID
|
|
||||||
import com.lsp.view.repository.bean.Size
|
|
||||||
import com.lsp.view.repository.bean.Tags
|
|
||||||
import com.lsp.view.util.Util
|
|
||||||
import kotlin.properties.Delegates
|
|
||||||
|
|
||||||
|
|
||||||
class PicActivity : AppCompatActivity() {
|
|
||||||
|
|
||||||
|
|
||||||
private val idList = ArrayList<ID>()
|
|
||||||
private val sizeList = ArrayList<Size>()
|
|
||||||
private lateinit var image: ImageView
|
|
||||||
private lateinit var photoView: PhotoView
|
|
||||||
private var shortAnnotationDuration by Delegates.notNull<Int>()
|
|
||||||
private var md5 : String?= null
|
|
||||||
|
|
||||||
|
|
||||||
companion object{
|
|
||||||
fun actionStartActivity(context: Context,id:String,sample_url:String,file_url:String,tags:String,
|
|
||||||
file_ext:String,file_size:String,md5:String,sample_height:Int,sample_width:Int){
|
|
||||||
val intent=Intent(context,PicActivity::class.java)
|
|
||||||
intent.putExtra("id", id)
|
|
||||||
intent.putExtra("sample_url", sample_url)
|
|
||||||
intent.putExtra("file_url", file_url)
|
|
||||||
intent.putExtra("tags", tags)
|
|
||||||
intent.putExtra("file_ext", file_ext)
|
|
||||||
intent.putExtra("file_size", file_size)
|
|
||||||
intent.putExtra("md5", md5)
|
|
||||||
intent.putExtra("sample_height",sample_height)
|
|
||||||
intent.putExtra("sample_width",sample_width)
|
|
||||||
context.startActivity(intent)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
setContentView(R.layout.activity_pic)
|
|
||||||
|
|
||||||
val toolbar = findViewById<Toolbar>(R.id.toolbar)
|
|
||||||
setSupportActionBar(toolbar)
|
|
||||||
supportActionBar?.setDisplayShowTitleEnabled(false)
|
|
||||||
|
|
||||||
image = findViewById(R.id.titleImage)
|
|
||||||
|
|
||||||
val sample_height = intent.getIntExtra("sample_height",-1)
|
|
||||||
val sample_width = intent.getIntExtra("sample_width",-1)
|
|
||||||
|
|
||||||
if (sample_width > sample_height){
|
|
||||||
image.scaleType = ImageView.ScaleType.CENTER_INSIDE
|
|
||||||
}
|
|
||||||
|
|
||||||
shortAnnotationDuration = resources.getInteger(android.R.integer.config_shortAnimTime)
|
|
||||||
val intent = intent
|
|
||||||
val tags = intent.getStringExtra("tags")
|
|
||||||
if (tags != null) {
|
|
||||||
loadTags(tags, "tags")
|
|
||||||
}
|
|
||||||
|
|
||||||
val file_size = intent.getStringExtra("file_size")
|
|
||||||
if (file_size != null) {
|
|
||||||
loadTags(file_size, "size")
|
|
||||||
}
|
|
||||||
md5 = intent.getStringExtra("md5")
|
|
||||||
|
|
||||||
val id = intent.getStringExtra("id")
|
|
||||||
if (id != null) {
|
|
||||||
loadTags(id, "id")
|
|
||||||
}
|
|
||||||
val sample_url = intent.getStringExtra("sample_url")
|
|
||||||
sample_url?.let {
|
|
||||||
loadPic(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
val file_url = intent.getStringExtra("file_url")
|
|
||||||
val file_ext = intent.getStringExtra("file_ext")
|
|
||||||
val download =
|
|
||||||
findViewById<FloatingActionButton>(
|
|
||||||
R.id.download
|
|
||||||
)
|
|
||||||
|
|
||||||
photoView = findViewById(R.id.photoView)
|
|
||||||
|
|
||||||
image.setOnClickListener {
|
|
||||||
photoView.apply {
|
|
||||||
alpha = 0f
|
|
||||||
visibility = View.VISIBLE
|
|
||||||
animate()
|
|
||||||
.alpha(1f)
|
|
||||||
.setDuration(shortAnnotationDuration.toLong())
|
|
||||||
.setListener(null)
|
|
||||||
}
|
|
||||||
Glide.with(this).load(sample_url).into(photoView)
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
photoView.setOnClickListener {
|
|
||||||
photoView.animate()
|
|
||||||
.alpha(0f)
|
|
||||||
.setDuration(shortAnnotationDuration.toLong())
|
|
||||||
.setListener(object : AnimatorListenerAdapter() {
|
|
||||||
override fun onAnimationEnd(animation: Animator) {
|
|
||||||
photoView.visibility = View.GONE
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
val share = findViewById<FloatingActionButton>(R.id.share)
|
|
||||||
share.setOnClickListener {
|
|
||||||
if (sample_url != null) {
|
|
||||||
Util.share(sample_url,this)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
download.setOnClickListener {
|
|
||||||
Util.download(file_url, file_ext, md5)
|
|
||||||
}
|
|
||||||
|
|
||||||
val f_btn = findViewById<FloatingActionButton>(R.id.float_btn)
|
|
||||||
val ctrl = findViewById<LinearLayout>(R.id.ctrl)
|
|
||||||
|
|
||||||
|
|
||||||
f_btn.setOnClickListener {
|
|
||||||
if (ctrl.visibility == View.VISIBLE)
|
|
||||||
ctrl.visibility = View.GONE
|
|
||||||
else
|
|
||||||
ctrl.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
|
|
||||||
val back = findViewById<ImageView>(R.id.back)
|
|
||||||
back.setOnClickListener {
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
|
|
||||||
onBackPressedDispatcher.addCallback{
|
|
||||||
if (photoView.visibility != View.GONE) {
|
|
||||||
photoView.animate()
|
|
||||||
.alpha(0f)
|
|
||||||
.setDuration(shortAnnotationDuration.toLong())
|
|
||||||
.setListener(object : AnimatorListenerAdapter() {
|
|
||||||
override fun onAnimationEnd(animation: Animator) {
|
|
||||||
photoView.visibility = View.GONE
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.dispatchKeyEvent(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadPic(url: String) {
|
|
||||||
|
|
||||||
val glideUrl = GlideUrl(
|
|
||||||
url,
|
|
||||||
LazyHeaders.Builder().addHeader(
|
|
||||||
"User-Agent",
|
|
||||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36"
|
|
||||||
).build()
|
|
||||||
)
|
|
||||||
Glide.with(this).load(glideUrl).listener(object : RequestListener<Drawable?> {
|
|
||||||
override fun onLoadFailed(
|
|
||||||
e: GlideException?,
|
|
||||||
model: Any?,
|
|
||||||
target: Target<Drawable?>?,
|
|
||||||
isFirstResource: Boolean
|
|
||||||
): Boolean {
|
|
||||||
e?.printStackTrace()
|
|
||||||
val back = findViewById<ImageView>(R.id.back)
|
|
||||||
Snackbar.make(back, R.string.toast_load_fail, Snackbar.LENGTH_LONG).setAction(R.string.button_check) {
|
|
||||||
AlertDialog.Builder(this@PicActivity).apply {
|
|
||||||
setTitle("Log")
|
|
||||||
if (e != null) {
|
|
||||||
setMessage(e.stackTraceToString())
|
|
||||||
}
|
|
||||||
setNegativeButton(R.string.button_ok, null)
|
|
||||||
create()
|
|
||||||
show()
|
|
||||||
}
|
|
||||||
}.show()
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResourceReady(
|
|
||||||
resource: Drawable?,
|
|
||||||
model: Any?,
|
|
||||||
target: Target<Drawable?>?,
|
|
||||||
dataSource: DataSource?,
|
|
||||||
isFirstResource: Boolean
|
|
||||||
): Boolean {
|
|
||||||
return false
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}).into(image)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun layoutManager(): FlexboxLayoutManager {
|
|
||||||
val manager = object : FlexboxLayoutManager(this, FlexDirection.ROW, FlexWrap.WRAP) {
|
|
||||||
override fun canScrollVertically(): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
manager.alignItems = AlignItems.CENTER
|
|
||||||
manager.justifyContent = JustifyContent.FLEX_START
|
|
||||||
|
|
||||||
return manager
|
|
||||||
}
|
|
||||||
|
|
||||||
//设置tags列表
|
|
||||||
//这写的很烂 得改
|
|
||||||
private fun loadTags(tags: String, type: String) {
|
|
||||||
val tagList = ArrayList<Tags>()
|
|
||||||
|
|
||||||
when (type) {
|
|
||||||
"tags" -> {
|
|
||||||
|
|
||||||
tagList.add(Tags("Tag"))
|
|
||||||
val list = tags.split(" ")
|
|
||||||
val tagRecyclerView =
|
|
||||||
findViewById<androidx.recyclerview.widget.RecyclerView>(R.id.tagRecyclerView)
|
|
||||||
tagRecyclerView.layoutManager = layoutManager()
|
|
||||||
for (tag in list) run {
|
|
||||||
tagList.add(Tags(tag))
|
|
||||||
}
|
|
||||||
val adapter = TagAdapter(tagList, this)
|
|
||||||
adapter.setOnItemClickListener(object : TagAdapter.OnItemClickListener {
|
|
||||||
override fun onItemClick(view: View, position: Int) {
|
|
||||||
val intent = Intent(this@PicActivity, MainActivity::class.java)
|
|
||||||
intent.putExtra("searchTag", tagList[position].tag)
|
|
||||||
startActivity(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
tagRecyclerView.adapter = adapter
|
|
||||||
}
|
|
||||||
"id" -> {
|
|
||||||
idList.add(ID("ID"))
|
|
||||||
idList.add(ID(tags))
|
|
||||||
val idRecyclerView =
|
|
||||||
findViewById<androidx.recyclerview.widget.RecyclerView>(R.id.idRecyclerView)
|
|
||||||
idRecyclerView.layoutManager = layoutManager()
|
|
||||||
val adapter = IdAdapter(idList,this)
|
|
||||||
idRecyclerView.adapter = adapter
|
|
||||||
}
|
|
||||||
"size" -> {
|
|
||||||
sizeList.add(Size("Size"))
|
|
||||||
sizeList.add(Size(tags))
|
|
||||||
val sizeRecyclerView =
|
|
||||||
findViewById<androidx.recyclerview.widget.RecyclerView>(R.id.sizeRecyclerView)
|
|
||||||
sizeRecyclerView.layoutManager = layoutManager()
|
|
||||||
val adapter = SizeAdapter(sizeList)
|
|
||||||
sizeRecyclerView.adapter = adapter
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package com.lsp.view.activity.pic
|
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.lsp.view.R
|
|
||||||
import com.lsp.view.repository.bean.Size
|
|
||||||
import java.math.RoundingMode
|
|
||||||
import java.text.DecimalFormat
|
|
||||||
|
|
||||||
class SizeAdapter(val tagList: List<Size>) : RecyclerView.Adapter<SizeAdapter.ViewHolder>() {
|
|
||||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
|
||||||
val tagText = view.findViewById<TextView>(R.id.tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
|
||||||
val view =
|
|
||||||
LayoutInflater.from(parent.context).inflate(R.layout.tag_item_layout, parent, false)
|
|
||||||
return ViewHolder(view)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
|
||||||
val tag = tagList[position]
|
|
||||||
if (position == 0) {
|
|
||||||
holder.tagText.text = tag.file_size
|
|
||||||
} else {
|
|
||||||
val sizeKb = tag.file_size.toFloat() / 1024
|
|
||||||
val format = DecimalFormat("0.##")
|
|
||||||
format.roundingMode = RoundingMode.FLOOR
|
|
||||||
val size = format.format(sizeKb)
|
|
||||||
holder.tagText.text = "$size KB"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
|
||||||
return tagList.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
package com.lsp.view.activity.pic
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.google.android.material.snackbar.Snackbar
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.reflect.TypeToken
|
|
||||||
import com.lsp.view.R
|
|
||||||
import com.lsp.view.repository.bean.Tags
|
|
||||||
|
|
||||||
class TagAdapter(val tagList: List<Tags>, val context: Context) :
|
|
||||||
RecyclerView.Adapter<TagAdapter.ViewHolder>() {
|
|
||||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
|
||||||
val tagText = view.findViewById<TextView>(R.id.tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var mOnItemClickListener: OnItemClickListener
|
|
||||||
|
|
||||||
interface OnItemClickListener {
|
|
||||||
fun onItemClick(view: View, position: Int)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setOnItemClickListener(mOnItemClickListener: OnItemClickListener) {
|
|
||||||
this.mOnItemClickListener = mOnItemClickListener
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
|
||||||
val view =
|
|
||||||
LayoutInflater.from(parent.context).inflate(R.layout.tag_item_layout, parent, false)
|
|
||||||
val viewHolder = ViewHolder(view)
|
|
||||||
viewHolder.tagText.setOnLongClickListener {
|
|
||||||
val position = viewHolder.adapterPosition
|
|
||||||
if (position == 0) {
|
|
||||||
//标题
|
|
||||||
return@setOnLongClickListener false
|
|
||||||
}
|
|
||||||
var tagsArray: ArrayList<Tags> = ArrayList()
|
|
||||||
val tagsArraySp = context.getSharedPreferences("tags_sp", Context.MODE_PRIVATE)
|
|
||||||
val tagsArrayJson = tagsArraySp.getString("array", null)
|
|
||||||
if (tagsArrayJson != null) {
|
|
||||||
val tagListType = object : TypeToken<ArrayList<Tags>>() {}.type
|
|
||||||
tagsArray = Gson().fromJson(tagsArrayJson, tagListType)
|
|
||||||
}
|
|
||||||
for (tag: Tags in tagsArray) {
|
|
||||||
if (tag.tag == viewHolder.tagText.text.toString()) {
|
|
||||||
Snackbar.make(viewHolder.tagText, R.string.toast_tag_exist, Snackbar.LENGTH_SHORT).show()
|
|
||||||
return@setOnLongClickListener true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tagsArray.add(Tags(viewHolder.tagText.text.toString()))
|
|
||||||
tagsArraySp.edit().putString("array", Gson().toJson(tagsArray)).apply()
|
|
||||||
Snackbar.make(viewHolder.tagText, R.string.toast_tag_add_fav, Snackbar.LENGTH_SHORT).show()
|
|
||||||
|
|
||||||
return@setOnLongClickListener true
|
|
||||||
}
|
|
||||||
return viewHolder
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
|
||||||
val tag = tagList[position]
|
|
||||||
holder.tagText.text = tag.tag
|
|
||||||
holder.tagText.setOnClickListener {
|
|
||||||
mOnItemClickListener.onItemClick(it, position)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
|
||||||
return tagList.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.lsp.view.bean
|
||||||
|
|
||||||
|
import android.os.Parcel
|
||||||
|
import android.os.Parcelable
|
||||||
|
|
||||||
|
open class Post(
|
||||||
|
open val postId: String,
|
||||||
|
open val rating: String,
|
||||||
|
open val sampleUrl:String,
|
||||||
|
open val fileUrl:String,
|
||||||
|
open val sampleHeight: Int,
|
||||||
|
open val sampleWidth: Int,
|
||||||
|
): Parcelable {
|
||||||
|
constructor(parcel: Parcel) : this(
|
||||||
|
parcel.readString()!!,
|
||||||
|
parcel.readString()!!,
|
||||||
|
parcel.readString()!!,
|
||||||
|
parcel.readString()!!,
|
||||||
|
parcel.readInt(),
|
||||||
|
parcel.readInt()
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun describeContents(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||||
|
dest.writeString(postId)
|
||||||
|
dest.writeString(rating)
|
||||||
|
dest.writeString(sampleUrl)
|
||||||
|
dest.writeString(fileUrl)
|
||||||
|
dest.writeInt(sampleHeight)
|
||||||
|
dest.writeInt(sampleWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmField
|
||||||
|
val CREATOR = object:Parcelable.Creator<Post> {
|
||||||
|
override fun createFromParcel(parcel: Parcel): Post {
|
||||||
|
return Post(parcel)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newArray(size: Int): Array<Post?> {
|
||||||
|
return arrayOfNulls(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.lsp.view.bean
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
class YandPost(
|
||||||
|
@SerializedName("file_url") override val fileUrl: String,
|
||||||
|
@SerializedName("sample_url") override val sampleUrl: String,
|
||||||
|
@SerializedName("sample_height") override val sampleHeight : Int,
|
||||||
|
@SerializedName("sample_width") override val sampleWidth: Int,
|
||||||
|
@SerializedName("file_ext") val fileExt: String,
|
||||||
|
@SerializedName("file_size") val fileSize: String,
|
||||||
|
@SerializedName("id") override val postId: String,
|
||||||
|
rating: String
|
||||||
|
):Post(postId, rating, sampleUrl,fileUrl,sampleHeight,sampleWidth)
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package com.lsp.view.fragment
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.AnimationUtils
|
||||||
|
import androidx.navigation.Navigation
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||||
|
import com.lsp.view.fragment.adapter.PostAdapter
|
||||||
|
import com.lsp.view.R
|
||||||
|
import com.lsp.view.activity.MainActivity
|
||||||
|
import com.lsp.view.bean.Post
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple [Fragment] subclass.
|
||||||
|
* create an instance of this fragment.
|
||||||
|
*/
|
||||||
|
class CollectFragment : Fragment() {
|
||||||
|
private lateinit var activityContext: MainActivity
|
||||||
|
private val collectAdapter by lazy {
|
||||||
|
PostAdapter(activityContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
activityContext = requireActivity() as MainActivity
|
||||||
|
|
||||||
|
activityContext.viewModel.getCollectList()
|
||||||
|
|
||||||
|
activityContext.viewModel.collectList.observe(this){
|
||||||
|
collectAdapter.pushNewData(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
// Inflate the layout for this fragment
|
||||||
|
return inflater.inflate(R.layout.fragment_collect, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
//刷新
|
||||||
|
val refresh =
|
||||||
|
view.findViewById<androidx.swiperefreshlayout.widget.SwipeRefreshLayout>(R.id.swipeRefreshLayout)
|
||||||
|
|
||||||
|
activityContext.viewModel.uiState.value.isRefreshing.observe(activityContext) {
|
||||||
|
refresh.isRefreshing = it
|
||||||
|
}
|
||||||
|
|
||||||
|
collectAdapter.setOnListItemClick(object : PostAdapter.OnListItemClick {
|
||||||
|
override fun setOnListItemClick(post: Post) {
|
||||||
|
val bundle = Bundle()
|
||||||
|
bundle.putParcelable("post",post)
|
||||||
|
Navigation.findNavController(view).navigate(R.id.action_collectFragment_to_imageFragment,bundle)
|
||||||
|
val slideOutAnimation = AnimationUtils.loadAnimation(context,
|
||||||
|
R.anim.slide_out_bottom
|
||||||
|
)
|
||||||
|
activityContext.bottomNav.startAnimation(slideOutAnimation)
|
||||||
|
activityContext.bottomNav.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
view.findViewById<RecyclerView>(R.id.recyclerview).apply {
|
||||||
|
val layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
|
||||||
|
this.layoutManager = layoutManager
|
||||||
|
this.adapter = collectAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
if (activityContext.bottomNav.visibility == View.GONE){
|
||||||
|
val slideOutAnimation = AnimationUtils.loadAnimation(context, R.anim.slide_on_bottom)
|
||||||
|
activityContext.bottomNav.startAnimation(slideOutAnimation)
|
||||||
|
activityContext.bottomNav.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
package com.lsp.view.fragment
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.ResolveInfo
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Environment
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.load.model.GlideUrl
|
||||||
|
import com.bumptech.glide.load.model.LazyHeaders
|
||||||
|
import com.google.android.material.bottomappbar.BottomAppBar
|
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
import com.lsp.view.R
|
||||||
|
import com.lsp.view.YandViewApplication
|
||||||
|
import com.lsp.view.activity.MainActivity
|
||||||
|
import com.lsp.view.bean.Post
|
||||||
|
import com.lsp.view.repository.datasource.model.Collect
|
||||||
|
import com.lsp.view.repository.datasource.model.Collect.Companion.toCollect
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class ImageFragment : Fragment() {
|
||||||
|
private val post by lazy {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
arguments?.getParcelable("post",Post::class.java)
|
||||||
|
}else{
|
||||||
|
arguments?.getParcelable("post")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Volatile private var isCollect = false
|
||||||
|
private val activityContext : MainActivity by lazy {
|
||||||
|
requireActivity() as MainActivity
|
||||||
|
}
|
||||||
|
private lateinit var collectBtn:MenuItem
|
||||||
|
private lateinit var collect:Collect
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
// Inflate the layout for this fragment
|
||||||
|
return inflater.inflate(R.layout.fragment_image, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
val bottomAppBar = view.findViewById<BottomAppBar>(R.id.bottomAppBar)
|
||||||
|
collectBtn = bottomAppBar.menu.findItem(R.id.collect_menu_btn)
|
||||||
|
collectBtn.setIcon(R.drawable.ic_bashline_unfavorite_24)
|
||||||
|
bottomAppBar.setOnMenuItemClickListener {
|
||||||
|
when(it.itemId){
|
||||||
|
R.id.share_menu_btn ->{
|
||||||
|
post?.sampleUrl?.let { it1 -> share(it1,activityContext) }
|
||||||
|
true
|
||||||
|
}
|
||||||
|
R.id.collect_menu_btn ->{
|
||||||
|
if (!isCollect){
|
||||||
|
collect = post!!.toCollect()
|
||||||
|
collectIt(collect)
|
||||||
|
}else{
|
||||||
|
unCollectIt(collect)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {false}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
post?.postId?.let {
|
||||||
|
val collectPost = activityContext.viewModel.getCollectByPostId(it)
|
||||||
|
val result = collectPost.await()
|
||||||
|
if (result != null){
|
||||||
|
collect = result
|
||||||
|
collectBtn.setIcon(R.drawable.ic_baseline_favorite_24)
|
||||||
|
isCollect = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val downloadBtn = view.findViewById<FloatingActionButton>(R.id.download_btn)
|
||||||
|
downloadBtn.setOnClickListener {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
if (post!=null){
|
||||||
|
download(post!!.fileUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (post!=null){
|
||||||
|
val imageContent = view.findViewById<ImageView>(R.id.image_content)
|
||||||
|
val glideUrl = GlideUrl(
|
||||||
|
post!!.sampleUrl,
|
||||||
|
LazyHeaders.Builder().addHeader("User-Agent", YandViewApplication.UA)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
Glide.with(this).load(glideUrl).into(imageContent)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun collectIt(collect: Collect){
|
||||||
|
activityContext.viewModel.addCollect(collect)
|
||||||
|
collectBtn.setIcon(R.drawable.ic_baseline_favorite_24)
|
||||||
|
isCollect = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun unCollectIt(collect:Collect){
|
||||||
|
activityContext.viewModel.removeCollect(collect)
|
||||||
|
collectBtn.setIcon(R.drawable.ic_bashline_unfavorite_24)
|
||||||
|
isCollect = false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun download(fileUrl: String){
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
activityContext.viewModel.postNewToast("Start download")
|
||||||
|
val result = (activityContext.application as YandViewApplication).downloadBinder.downloadImage(fileUrl)
|
||||||
|
if (result.isSuccess){
|
||||||
|
activityContext.viewModel.postNewToast("Download successfully")
|
||||||
|
}else{
|
||||||
|
val exception = result.exceptionOrNull()
|
||||||
|
activityContext.viewModel.postNewToast(exception?.message.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun share(url:String,context: Context){
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
val bitmap = Glide.with(context).asBitmap().load(url).submit().get()
|
||||||
|
val path = File("${context.cacheDir}/image")
|
||||||
|
val split = url.split("/")
|
||||||
|
val fileName = split[split.size - 1]
|
||||||
|
if (!path.exists())
|
||||||
|
path.mkdirs()
|
||||||
|
|
||||||
|
|
||||||
|
var file = File("${context.cacheDir}/image/$fileName")
|
||||||
|
val downloadFile =
|
||||||
|
File("${Environment.getExternalStorageDirectory()}/${Environment.DIRECTORY_PICTURES}/LspMake/$fileName")
|
||||||
|
|
||||||
|
if (downloadFile.exists()){
|
||||||
|
file = downloadFile
|
||||||
|
}else if (!file.exists()) {
|
||||||
|
file.outputStream().apply {
|
||||||
|
bitmap.compress(Bitmap.CompressFormat.PNG, 100, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val imageUri = FileProvider.getUriForFile(
|
||||||
|
context,
|
||||||
|
"com.lsp.view.fileprovider",
|
||||||
|
file
|
||||||
|
|
||||||
|
)
|
||||||
|
context.grantUriPermission(
|
||||||
|
"com.lsp.view",
|
||||||
|
imageUri,
|
||||||
|
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||||
|
)
|
||||||
|
val shareIntent = Intent(Intent.ACTION_SEND)
|
||||||
|
shareIntent.type = "image/*"
|
||||||
|
shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri)
|
||||||
|
shareIntent.putExtra(Intent.EXTRA_TITLE,fileName)
|
||||||
|
val intent = Intent.createChooser(shareIntent, R.string.title_share.toString())
|
||||||
|
val resInfoList: List<ResolveInfo> = if (Build.VERSION.SDK_INT < 33) {
|
||||||
|
context.packageManager
|
||||||
|
.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
|
||||||
|
} else {
|
||||||
|
context.packageManager.queryIntentActivities(
|
||||||
|
intent,
|
||||||
|
PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
for (resolveInfo in resInfoList) {
|
||||||
|
val packageName = resolveInfo.activityInfo.packageName
|
||||||
|
context.grantUriPermission(
|
||||||
|
packageName,
|
||||||
|
imageUri,
|
||||||
|
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
|
)
|
||||||
|
}
|
||||||
|
context.startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package com.lsp.view.fragment
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.AnimationUtils
|
||||||
|
import android.view.inputmethod.EditorInfo
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.navigation.Navigation
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||||
|
import com.google.android.material.search.SearchBar
|
||||||
|
import com.google.android.material.search.SearchView
|
||||||
|
import com.lsp.view.fragment.adapter.PostAdapter
|
||||||
|
import com.lsp.view.R
|
||||||
|
import com.lsp.view.activity.MainActivity
|
||||||
|
import com.lsp.view.bean.Post
|
||||||
|
import com.lsp.view.model.MainViewModel
|
||||||
|
|
||||||
|
class PostListFragment:Fragment() {
|
||||||
|
private val viewModel: MainViewModel by lazy {
|
||||||
|
ViewModelProvider(requireActivity(),MainViewModel.provideFactory(activityContext.repository,requireContext(),this)).get(MainViewModel::class.java)
|
||||||
|
}
|
||||||
|
private lateinit var activityContext: MainActivity
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
return inflater.inflate(R.layout.fragment_list, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
activityContext = requireActivity() as MainActivity
|
||||||
|
val searchBar = view.findViewById<SearchBar>(R.id.search_bar)
|
||||||
|
|
||||||
|
val searchView = view.findViewById<SearchView>(R.id.search_view)
|
||||||
|
searchView.editText.setOnEditorActionListener { v, actionId, event ->
|
||||||
|
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
||||||
|
viewModel.fetchPostBySearch(searchView.text.toString())
|
||||||
|
searchBar.setText(searchView.text)
|
||||||
|
searchView.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
return@setOnEditorActionListener false
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.uiState.value.nowSearchText.observe(requireActivity()){
|
||||||
|
searchView.setText(it)
|
||||||
|
searchBar.setText(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
//刷新
|
||||||
|
val refresh =
|
||||||
|
view.findViewById<androidx.swiperefreshlayout.widget.SwipeRefreshLayout>(R.id.swipeRefreshLayout)
|
||||||
|
viewModel.uiState.value.isRefreshing.observe(activityContext) {
|
||||||
|
refresh.isRefreshing = it
|
||||||
|
}
|
||||||
|
refresh.setOnRefreshListener {
|
||||||
|
viewModel.fetchPostByRefresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.postList.observe(activityContext){
|
||||||
|
viewModel.adapter.pushNewData(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.adapter.apply {
|
||||||
|
setLoadMoreListener(object : PostAdapter.OnScrollToBottom {
|
||||||
|
override fun event(position: Int) {
|
||||||
|
viewModel.fetchMore()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
view.findViewById<RecyclerView>(R.id.recyclerview).apply {
|
||||||
|
val layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
|
||||||
|
this.layoutManager = layoutManager
|
||||||
|
this.adapter = viewModel.adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.adapter.setOnListItemClick(object : PostAdapter.OnListItemClick {
|
||||||
|
override fun setOnListItemClick(post: Post) {
|
||||||
|
val bundle = Bundle()
|
||||||
|
bundle.putParcelable("post",post)
|
||||||
|
Navigation.findNavController(view).navigate(R.id.action_postListFragment_to_imageFragment,bundle)
|
||||||
|
val slideOutAnimation = AnimationUtils.loadAnimation(context,
|
||||||
|
R.anim.slide_out_bottom
|
||||||
|
)
|
||||||
|
activityContext.bottomNav.startAnimation(slideOutAnimation)
|
||||||
|
activityContext.bottomNav.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
if (activityContext.bottomNav.visibility == View.GONE){
|
||||||
|
val slideOutAnimation = AnimationUtils.loadAnimation(context, R.anim.slide_on_bottom)
|
||||||
|
activityContext.bottomNav.startAnimation(slideOutAnimation)
|
||||||
|
activityContext.bottomNav.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+48
-49
@@ -1,4 +1,4 @@
|
|||||||
package com.lsp.view.activity.main
|
package com.lsp.view.fragment.adapter
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@@ -10,34 +10,51 @@ 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.YandViewApplication
|
||||||
import com.lsp.view.repository.bean.YandPost
|
import com.lsp.view.bean.Post
|
||||||
|
|
||||||
|
|
||||||
class PostAdapter(val context: Context,private val postList: ArrayList<YandPost> = ArrayList()):
|
class PostAdapter(val context: Context,private val postList: ArrayList<Post> = ArrayList()):
|
||||||
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 var inBottom:Boolean = false//当前列表是否在底部
|
||||||
var isAppendData = false//数据追加标志
|
@Volatile private var isProcess:Boolean = false
|
||||||
|
|
||||||
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.image)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pushNewData(list: List<YandPost>) {
|
fun pushNewData(list: List<Post>) {
|
||||||
val oldSize = postList.size
|
if (!isProcess) {
|
||||||
postList.clear()
|
isProcess = true
|
||||||
notifyItemRangeRemoved(0,oldSize)
|
if (inBottom) {
|
||||||
postList.addAll(list)
|
//在底部,则追加数据
|
||||||
notifyItemRangeInserted(0, list.size)
|
val pos = postList.size
|
||||||
|
postList.addAll(list)
|
||||||
|
notifyItemRangeInserted(pos - 1, list.size)
|
||||||
|
} else {
|
||||||
|
//不在则刷新数据
|
||||||
|
val oldSize = postList.size
|
||||||
|
postList.clear()
|
||||||
|
notifyItemRangeRemoved(0, oldSize)
|
||||||
|
postList.addAll(list)
|
||||||
|
notifyItemRangeInserted(0, list.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isProcess = false
|
||||||
|
inBottom = false//加入新数据后不在底部,若仍在底部说明无更多数据,也不必处理
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun appendDate(list: List<YandPost>){
|
|
||||||
val pos = postList.size
|
private lateinit var mOnListItemClick: OnListItemClick
|
||||||
postList.addAll(list)
|
interface OnListItemClick {
|
||||||
notifyItemRangeInserted(pos-1, list.size)
|
fun setOnListItemClick(post:Post)
|
||||||
isAppendData = false
|
}
|
||||||
|
fun setOnListItemClick(mOnListItemClick: OnListItemClick) {
|
||||||
|
this.mOnListItemClick = mOnListItemClick
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
@@ -46,27 +63,7 @@ class PostAdapter(val context: Context,private val postList: ArrayList<YandPost>
|
|||||||
|
|
||||||
viewHolder.picImage.setOnClickListener {
|
viewHolder.picImage.setOnClickListener {
|
||||||
val position = viewHolder.adapterPosition
|
val position = viewHolder.adapterPosition
|
||||||
// Log.w("position", position.toString())
|
mOnListItemClick.setOnListItemClick(postList[position])
|
||||||
// Log.w("url", postList.value?.get(position)?.sample_url)
|
|
||||||
// Log.w("rating", postList[position].rating)
|
|
||||||
var file_ext = postList[position].file_ext
|
|
||||||
|
|
||||||
if (file_ext == null){
|
|
||||||
val strarr = postList[position].sample_url.split(".")
|
|
||||||
file_ext = strarr[strarr.lastIndex]
|
|
||||||
}
|
|
||||||
|
|
||||||
PicActivity.actionStartActivity(
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -93,10 +90,10 @@ class PostAdapter(val context: Context,private val postList: ArrayList<YandPost>
|
|||||||
}
|
}
|
||||||
for(index in p..last){
|
for(index in p..last){
|
||||||
if (p>6) {
|
if (p>6) {
|
||||||
val source: String = postList[index].sample_url
|
val source: String = postList[index].sampleUrl
|
||||||
val glideUrl = GlideUrl(
|
val glideUrl = GlideUrl(
|
||||||
source,
|
source,
|
||||||
LazyHeaders.Builder().addHeader("User-Agent", UA)
|
LazyHeaders.Builder().addHeader("User-Agent", YandViewApplication.UA)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
Glide.with(context).download(glideUrl).preload()
|
Glide.with(context).download(glideUrl).preload()
|
||||||
@@ -112,10 +109,10 @@ class PostAdapter(val context: Context,private val postList: ArrayList<YandPost>
|
|||||||
|
|
||||||
val post = postList[position]
|
val post = postList[position]
|
||||||
|
|
||||||
val source: String = post.sample_url
|
val source: String = post.sampleUrl
|
||||||
|
|
||||||
val height = postList[position].sample_height
|
val height = postList[position].sampleHeight
|
||||||
val width = postList[position].sample_width
|
val width = postList[position].sampleWidth
|
||||||
|
|
||||||
//图片过长则缩减高度以保证显示完整
|
//图片过长则缩减高度以保证显示完整
|
||||||
if (width > height){
|
if (width > height){
|
||||||
@@ -127,22 +124,24 @@ class PostAdapter(val context: Context,private val postList: ArrayList<YandPost>
|
|||||||
|
|
||||||
val glideUrl = GlideUrl(
|
val glideUrl = GlideUrl(
|
||||||
source,
|
source,
|
||||||
LazyHeaders.Builder().addHeader("User-Agent", UA)
|
LazyHeaders.Builder().addHeader("User-Agent", YandViewApplication.UA)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
Glide.with(context).load(glideUrl).into(holder.picImage)
|
Glide.with(context).load(glideUrl).into(holder.picImage)
|
||||||
|
|
||||||
if (position == postList.size - 1 && postList.size > 6) {
|
if (position == postList.size - 1 && postList.size > 6 ) {
|
||||||
//到达底部
|
//到达底部
|
||||||
mScrollToBottom.event(position)
|
inBottom = true
|
||||||
|
if (this::mScrollToBottom.isInitialized) {
|
||||||
|
mScrollToBottom.event(position)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
val size = postList.size
|
return postList.size
|
||||||
return size
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -8,33 +8,51 @@ import androidx.lifecycle.MutableLiveData
|
|||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.lsp.view.activity.main.PostAdapter
|
import com.lsp.view.fragment.adapter.PostAdapter
|
||||||
import com.lsp.view.repository.PostRepository
|
import com.lsp.view.repository.network.PostRepository
|
||||||
import androidx.savedstate.SavedStateRegistryOwner
|
import androidx.savedstate.SavedStateRegistryOwner
|
||||||
import com.lsp.view.repository.bean.Post
|
import com.lsp.view.YandViewApplication
|
||||||
import com.lsp.view.repository.bean.YandPost
|
import com.lsp.view.bean.YandPost
|
||||||
|
import com.lsp.view.repository.datasource.CollectDatabase
|
||||||
|
import com.lsp.view.repository.datasource.CollectRepository
|
||||||
|
import com.lsp.view.repository.datasource.CollectRepositoryImpl
|
||||||
|
import com.lsp.view.repository.datasource.model.Collect
|
||||||
import com.lsp.view.repository.exception.NetworkErrorException
|
import com.lsp.view.repository.exception.NetworkErrorException
|
||||||
|
import com.lsp.view.ui.UiState
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class MainViewModel(private val repository: PostRepository,context: Context):ViewModel() {
|
class MainViewModel(private val repository: PostRepository, context: Context):ViewModel() {
|
||||||
private val _uiState = MutableStateFlow(UiState())
|
private val _uiState = MutableStateFlow(UiState())
|
||||||
val uiState:StateFlow<UiState>
|
val uiState:StateFlow<UiState>
|
||||||
get() = _uiState.asStateFlow()
|
get() = _uiState.asStateFlow()
|
||||||
private var fetchJob: Job? = null
|
private var fetchJob: Job? = null
|
||||||
private val TAG = this::class.java.simpleName
|
private val TAG = this::class.java.simpleName
|
||||||
private val _errorMessage = MutableLiveData<String>()
|
private val _toastMessage = MutableLiveData<String>()
|
||||||
val errorMessage
|
val toastMessage
|
||||||
get() = _errorMessage as LiveData<String>
|
get() = _toastMessage as LiveData<String>
|
||||||
|
|
||||||
private val _postList = MutableLiveData<ArrayList<YandPost>>()
|
private val _postList = MutableLiveData<ArrayList<YandPost>>()
|
||||||
val postList get() = _postList as LiveData<ArrayList<YandPost>>
|
val postList get() = _postList as LiveData<ArrayList<YandPost>>
|
||||||
|
val adapter by lazy {
|
||||||
|
fetchPostByRefresh()
|
||||||
|
PostAdapter(context)
|
||||||
|
}
|
||||||
|
private val _collectList:MutableLiveData<List<Collect>> = MutableLiveData()
|
||||||
|
val collectList:LiveData<List<Collect>>
|
||||||
|
get() = _collectList
|
||||||
|
|
||||||
|
private val collectRepository: CollectRepository by lazy {
|
||||||
|
CollectRepositoryImpl(CollectDatabase.getDatabase(context).collectDao())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Volatile private var isProcessing = false
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun provideFactory(
|
fun provideFactory(
|
||||||
@@ -76,7 +94,7 @@ class MainViewModel(private val repository: PostRepository,context: Context):Vie
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetchNewPost(append:Boolean = false){
|
private fun fetchNewPost(){
|
||||||
fetchJob?.cancel()
|
fetchJob?.cancel()
|
||||||
fetchJob = viewModelScope.launch(Dispatchers.IO) {
|
fetchJob = viewModelScope.launch(Dispatchers.IO) {
|
||||||
_uiState.value.isRefreshing.postValue(true)
|
_uiState.value.isRefreshing.postValue(true)
|
||||||
@@ -88,7 +106,7 @@ class MainViewModel(private val repository: PostRepository,context: Context):Vie
|
|||||||
))
|
))
|
||||||
|
|
||||||
}catch (e:NetworkErrorException){
|
}catch (e:NetworkErrorException){
|
||||||
_errorMessage.postValue(e.message.toString())
|
postNewToast(e.message.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
_uiState.value.isRefreshing.postValue(false)
|
_uiState.value.isRefreshing.postValue(false)
|
||||||
@@ -118,7 +136,7 @@ class MainViewModel(private val repository: PostRepository,context: Context):Vie
|
|||||||
|
|
||||||
fun fetchMore(){
|
fun fetchMore(){
|
||||||
_uiState.value.nowPage++
|
_uiState.value.nowPage++
|
||||||
fetchNewPost(true)
|
fetchNewPost()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateSafeMode(mode:Boolean){
|
fun updateSafeMode(mode:Boolean){
|
||||||
@@ -132,4 +150,40 @@ class MainViewModel(private val repository: PostRepository,context: Context):Vie
|
|||||||
_uiState.value.nowSourceName.postValue(source)
|
_uiState.value.nowSourceName.postValue(source)
|
||||||
fetchPostByRefresh()
|
fetchPostByRefresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getCollectList(){
|
||||||
|
viewModelScope.launch {
|
||||||
|
_collectList.postValue(collectRepository.getAllCollect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addCollect(collect: Collect){
|
||||||
|
if (!isProcessing){
|
||||||
|
viewModelScope.launch {
|
||||||
|
collectRepository.addNewCollect(collect)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeCollect(collect:Collect){
|
||||||
|
|
||||||
|
if (!isProcessing){
|
||||||
|
viewModelScope.launch {
|
||||||
|
collectRepository.removeCollect(collect)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getCollectByPostId(postId:String) = viewModelScope.async {
|
||||||
|
val type = YandViewApplication.context?.getSharedPreferences("com.lsp.view_preferences",Context.MODE_PRIVATE)?.getString("source_name", "yande.re")
|
||||||
|
collectRepository.getCollectByPostId(postId,type!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun postNewToast(content:String){
|
||||||
|
_toastMessage.postValue(content)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
package com.lsp.view.repository.bean
|
|
||||||
|
|
||||||
class Author(val author: String)
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
package com.lsp.view.repository.bean
|
|
||||||
|
|
||||||
class ID(val id: String)
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package com.lsp.view.repository.bean
|
|
||||||
|
|
||||||
open class Post(
|
|
||||||
val id: String,
|
|
||||||
val rating: String,
|
|
||||||
val author: String,
|
|
||||||
)
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
package com.lsp.view.repository.bean
|
|
||||||
|
|
||||||
class Size(val file_size: String)
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
package com.lsp.view.repository.bean
|
|
||||||
|
|
||||||
class Tags(val tag: String)
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package com.lsp.view.repository.bean
|
|
||||||
|
|
||||||
class YandPost(
|
|
||||||
val preview_url: String,
|
|
||||||
val file_url: String,
|
|
||||||
val sample_url: String,
|
|
||||||
val tags: String,
|
|
||||||
val file_ext: String,
|
|
||||||
val file_size: String,
|
|
||||||
val sample_height : Int,
|
|
||||||
val sample_width: Int,
|
|
||||||
id: String,
|
|
||||||
rating: String,
|
|
||||||
author: String,
|
|
||||||
val md5 : String
|
|
||||||
):Post(id, rating, author)
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.lsp.view.repository.datasource
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.room.Database
|
||||||
|
import androidx.room.Room
|
||||||
|
import androidx.room.RoomDatabase
|
||||||
|
import com.lsp.view.repository.datasource.dao.CollectDao
|
||||||
|
import com.lsp.view.repository.datasource.model.Collect
|
||||||
|
|
||||||
|
@Database(entities = [Collect::class], version = 1,exportSchema = false)
|
||||||
|
abstract class CollectDatabase: RoomDatabase(){
|
||||||
|
abstract fun collectDao():CollectDao
|
||||||
|
companion object{
|
||||||
|
@Volatile
|
||||||
|
private var Instance:CollectDatabase? = null
|
||||||
|
|
||||||
|
fun getDatabase(context: Context):CollectDatabase{
|
||||||
|
return Instance?: synchronized(this) {
|
||||||
|
Room.databaseBuilder(context,CollectDatabase::class.java,"collect_database").build().also { Instance = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.lsp.view.repository.datasource
|
||||||
|
|
||||||
|
import com.lsp.view.repository.datasource.model.Collect
|
||||||
|
|
||||||
|
interface CollectRepository {
|
||||||
|
suspend fun addNewCollect(collect: Collect)
|
||||||
|
suspend fun getAllCollect():List<Collect>
|
||||||
|
suspend fun getCollectByPostId(postId:String,type:String):Collect?
|
||||||
|
suspend fun removeCollect(collect: Collect)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.lsp.view.repository.datasource
|
||||||
|
|
||||||
|
import com.lsp.view.repository.datasource.dao.CollectDao
|
||||||
|
import com.lsp.view.repository.datasource.model.Collect
|
||||||
|
|
||||||
|
class CollectRepositoryImpl(private val collectDao:CollectDao):CollectRepository {
|
||||||
|
override suspend fun addNewCollect(collect: Collect) {
|
||||||
|
collectDao.insert(collect)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getAllCollect(): List<Collect> {
|
||||||
|
return collectDao.getAllCollect()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getCollectByPostId(postId: String,type:String): Collect? {
|
||||||
|
return collectDao.getCollectByPostId(postId,type)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun removeCollect(collect: Collect) {
|
||||||
|
collectDao.delete(collect.postId,collect.type)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.lsp.view.repository.datasource.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import androidx.room.Query
|
||||||
|
import com.lsp.view.repository.datasource.model.Collect
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface CollectDao {
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
suspend fun insert(collect:Collect)
|
||||||
|
@Query("select * from collect")
|
||||||
|
suspend fun getAllCollect():List<Collect>
|
||||||
|
@Query("delete from collect where post_id = :postId and type = :type")
|
||||||
|
suspend fun delete(postId: String,type: String)
|
||||||
|
@Query("select * from collect where post_id = :postId and type = :type")
|
||||||
|
suspend fun getCollectByPostId(postId:String,type:String):Collect?
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.lsp.view.repository.datasource.model
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import com.lsp.view.YandViewApplication
|
||||||
|
import com.lsp.view.bean.Post
|
||||||
|
|
||||||
|
@Entity(tableName = "collect")
|
||||||
|
data class Collect(
|
||||||
|
@PrimaryKey(autoGenerate = true) var id:Int = 0,
|
||||||
|
@ColumnInfo(name = "post_id")override val postId: String,
|
||||||
|
@ColumnInfo(name = "sample_url")override val sampleUrl:String,
|
||||||
|
@ColumnInfo(name = "rating")override val rating:String,
|
||||||
|
@ColumnInfo(name = "file_url")override val fileUrl:String,
|
||||||
|
@ColumnInfo(name = "sampleHeight") override val sampleHeight:Int,
|
||||||
|
@ColumnInfo(name = "sampleWeight") override val sampleWidth:Int,
|
||||||
|
@ColumnInfo(name = "type")val type:String
|
||||||
|
):Post(postId,rating,sampleUrl,fileUrl,sampleHeight,sampleWidth){
|
||||||
|
constructor(
|
||||||
|
postId: String,
|
||||||
|
sampleUrl:String,
|
||||||
|
rating:String,
|
||||||
|
fileUrl:String,
|
||||||
|
sampleHeight:Int,
|
||||||
|
sampleWeight:Int,
|
||||||
|
): this(0, postId, sampleUrl, rating, fileUrl, sampleHeight, sampleWeight,
|
||||||
|
YandViewApplication.context?.getSharedPreferences("com.lsp.view_preferences",Context.MODE_PRIVATE)?.getString("source_name", "yande.re")!!)
|
||||||
|
companion object{
|
||||||
|
fun Post.toCollect():Collect = Collect(this.postId,this.sampleUrl,this.rating,this.fileUrl,this.sampleHeight,this.sampleWidth )
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+5
-5
@@ -1,11 +1,11 @@
|
|||||||
package com.lsp.view.repository
|
package com.lsp.view.repository.network
|
||||||
|
|
||||||
import com.lsp.view.R
|
import com.lsp.view.R
|
||||||
import com.lsp.view.YandViewApplication
|
import com.lsp.view.YandViewApplication
|
||||||
import com.lsp.view.repository.exception.UnableConstructObjectException
|
import com.lsp.view.repository.exception.UnableConstructObjectException
|
||||||
import com.lsp.view.repository.api.PostApi
|
import com.lsp.view.repository.network.api.PostApi
|
||||||
import com.lsp.view.repository.api.PostApiImpl
|
import com.lsp.view.repository.network.api.PostApiImpl
|
||||||
import com.lsp.view.repository.bean.YandPost
|
import com.lsp.view.bean.YandPost
|
||||||
|
|
||||||
class PostDataSource {
|
class PostDataSource {
|
||||||
private val api: PostApi = PostApiImpl()
|
private val api: PostApi = PostApiImpl()
|
||||||
@@ -25,7 +25,7 @@ data class Load(
|
|||||||
lateinit var source:String
|
lateinit var source:String
|
||||||
|
|
||||||
companion object{
|
companion object{
|
||||||
fun Builder(tags: String?, page: Int, safe:Boolean):Load{
|
fun Builder(tags: String?, page: Int, safe:Boolean): Load {
|
||||||
val sourceNameArray = YandViewApplication.context!!.resources.getStringArray(R.array.pic_source)
|
val sourceNameArray = YandViewApplication.context!!.resources.getStringArray(R.array.pic_source)
|
||||||
val sourceUrlArray = YandViewApplication.context!!.resources.getStringArray(R.array.url_source)
|
val sourceUrlArray = YandViewApplication.context!!.resources.getStringArray(R.array.url_source)
|
||||||
val configSp = YandViewApplication.context?.getSharedPreferences("com.lsp.view_preferences", 0)
|
val configSp = YandViewApplication.context?.getSharedPreferences("com.lsp.view_preferences", 0)
|
||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
package com.lsp.view.repository
|
package com.lsp.view.repository.network
|
||||||
|
|
||||||
import com.lsp.view.repository.bean.YandPost
|
import com.lsp.view.bean.YandPost
|
||||||
|
|
||||||
|
|
||||||
class PostRepository {
|
class PostRepository {
|
||||||
+5
-5
@@ -1,8 +1,8 @@
|
|||||||
package com.lsp.view.repository.api
|
package com.lsp.view.repository.network.api
|
||||||
|
|
||||||
import com.lsp.view.repository.Load
|
import com.lsp.view.repository.network.Load
|
||||||
import com.lsp.view.repository.bean.Post
|
import com.lsp.view.bean.Post
|
||||||
import com.lsp.view.repository.bean.YandPost
|
import com.lsp.view.bean.YandPost
|
||||||
import com.lsp.view.repository.exception.NetworkErrorException
|
import com.lsp.view.repository.exception.NetworkErrorException
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
|
|
||||||
@@ -35,5 +35,5 @@ interface PostApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun fetchNewPost(load:Load):ArrayList<YandPost>
|
suspend fun fetchNewPost(load: Load):ArrayList<YandPost>
|
||||||
}
|
}
|
||||||
+5
-5
@@ -1,9 +1,9 @@
|
|||||||
package com.lsp.view.repository.api
|
package com.lsp.view.repository.network.api
|
||||||
|
|
||||||
import com.lsp.view.repository.Load
|
import com.lsp.view.repository.network.Load
|
||||||
import com.lsp.view.retrofit.PostService
|
import com.lsp.view.repository.network.retrofit.PostService
|
||||||
import com.lsp.view.retrofit.ServiceCreator
|
import com.lsp.view.repository.network.retrofit.ServiceCreator
|
||||||
import com.lsp.view.repository.bean.YandPost
|
import com.lsp.view.bean.YandPost
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
package com.lsp.view.retrofit
|
package com.lsp.view.repository.network.retrofit
|
||||||
|
|
||||||
import com.lsp.view.repository.bean.YandPost
|
import com.lsp.view.bean.YandPost
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.lsp.view.retrofit
|
package com.lsp.view.repository.network.retrofit
|
||||||
|
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
@@ -1,146 +1,75 @@
|
|||||||
package com.lsp.view.service
|
package com.lsp.view.service
|
||||||
|
|
||||||
|
import android.accounts.NetworkErrorException
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Context
|
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.Util
|
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.security.MessageDigest
|
import java.io.Serializable
|
||||||
import kotlin.concurrent.thread
|
|
||||||
|
|
||||||
class DownloadService : Service() {
|
class DownloadService : Service() {
|
||||||
private val mBinder = DownloadBinder(this)
|
private val mBinder = DownloadBinder(this)
|
||||||
|
|
||||||
class DownloadBinder(val context: Context) : Binder() {
|
class DownloadBinder(val context: Context) : Binder() {
|
||||||
|
|
||||||
fun callBack(handler: Handler,status:Int){
|
fun downloadImage(fileUrl: String):Result<Serializable> {
|
||||||
val msg = Message.obtain()
|
|
||||||
msg.obj = status
|
|
||||||
handler.sendMessage(msg)
|
|
||||||
|
|
||||||
}
|
val fileDir =
|
||||||
fun downloadPic(file_url: String, end: String,handler: Handler,md5 : String?) {
|
File("${Environment.getExternalStorageDirectory()}/${Environment.DIRECTORY_PICTURES}/LspMake/")
|
||||||
|
if (!fileDir.exists()) {
|
||||||
thread {
|
fileDir.mkdirs()
|
||||||
val FileD =
|
|
||||||
File("${Environment.getExternalStorageDirectory()}/${Environment.DIRECTORY_PICTURES}/LspMake/")
|
|
||||||
if (FileD.exists()) {
|
|
||||||
val file =
|
|
||||||
File("${Environment.getExternalStorageDirectory()}/${Environment.DIRECTORY_PICTURES}/LspMake/$md5.$end")
|
|
||||||
|
|
||||||
if (file.exists()){
|
|
||||||
callBack(handler,Util.FILE_EXISTS)
|
|
||||||
return@thread
|
|
||||||
}
|
|
||||||
|
|
||||||
val fos = FileOutputStream(file)
|
|
||||||
try {
|
|
||||||
|
|
||||||
val client = OkHttpClient()
|
|
||||||
val request = Request.Builder()
|
|
||||||
.url(file_url)
|
|
||||||
.build()
|
|
||||||
val response = client.newCall(request).execute()
|
|
||||||
val responseData = response.body()?.bytes()
|
|
||||||
if (response.code() == 200) {
|
|
||||||
fos.write(responseData)
|
|
||||||
|
|
||||||
//通知媒体更新
|
|
||||||
MediaScannerConnection.scanFile(
|
|
||||||
context, arrayOf(file.path),
|
|
||||||
null, null
|
|
||||||
)
|
|
||||||
if (md5 == getFileMD5(file.path)) {
|
|
||||||
callBack(handler, Util.DOWNLOAD_SUCCESS)
|
|
||||||
} else {
|
|
||||||
file.delete()
|
|
||||||
callBack(handler,Util.MD5_COMPARE_ERROR)
|
|
||||||
}
|
|
||||||
|
|
||||||
return@thread
|
|
||||||
|
|
||||||
} else {
|
|
||||||
file.delete()
|
|
||||||
callBack(handler, Util.NETWORK_ERROR)
|
|
||||||
return@thread
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
callBack(handler, Util.DOWNLOAD_ERROR)
|
|
||||||
return@thread
|
|
||||||
} finally {
|
|
||||||
fos.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
FileD.mkdirs()
|
|
||||||
downloadPic(file_url, end, handler, md5)
|
|
||||||
}
|
|
||||||
callBack(handler,Util.DOWNLOAD_ERROR)
|
|
||||||
}
|
}
|
||||||
}
|
val split = fileUrl.split("/")
|
||||||
|
val fileName = split[split.size - 1]
|
||||||
/**
|
val file =
|
||||||
* 获取文件MD5
|
File("${Environment.getExternalStorageDirectory()}/${Environment.DIRECTORY_PICTURES}/LspMake/$fileName")
|
||||||
*/
|
if (file.exists()) {
|
||||||
fun getFileMD5(path: String?): String? {
|
return Result.failure<Exception>(Exception("File exists"))
|
||||||
if (path.isNullOrEmpty()) {
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
var digest: MessageDigest? = null
|
val fos = FileOutputStream(file)
|
||||||
var fileIS: FileInputStream? = null
|
|
||||||
val buffer = ByteArray(1024)
|
|
||||||
var len = 0
|
|
||||||
try {
|
try {
|
||||||
digest = MessageDigest.getInstance("MD5")
|
val client = OkHttpClient()
|
||||||
val oldF = File(path)
|
val request = Request.Builder()
|
||||||
fileIS = FileInputStream(oldF)
|
.url(fileUrl)
|
||||||
while (fileIS.read(buffer).also { len = it } != -1) {
|
.build()
|
||||||
digest.update(buffer, 0, len)
|
val response = client.newCall(request).execute()
|
||||||
|
val responseData = response.body()?.bytes()
|
||||||
|
return if (response.code() == 200) {
|
||||||
|
fos.write(responseData)
|
||||||
|
//通知媒体更新
|
||||||
|
MediaScannerConnection.scanFile(
|
||||||
|
context, arrayOf(file.path),
|
||||||
|
null, null
|
||||||
|
)
|
||||||
|
Result.success("File download successfully")
|
||||||
|
} else {
|
||||||
|
file.delete()
|
||||||
|
Result.failure<Exception>(NetworkErrorException("Connection timed out"))
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
Result.failure<Exception>(e)
|
||||||
return null
|
} finally {
|
||||||
}finally {
|
fos.close()
|
||||||
fileIS?.close()
|
|
||||||
}
|
|
||||||
return bytesToHexString(digest?.digest())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun bytesToHexString(src: ByteArray?): String? {
|
|
||||||
val result = StringBuilder("")
|
|
||||||
if (src?.isEmpty()==true) {
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
src?.forEach {
|
return Result.failure(Exception("Unknown error"))
|
||||||
var i = it.toInt()
|
|
||||||
//这里需要对b与0xff做位与运算,
|
|
||||||
//若b为负数,强制转换将高位位扩展,导致错误,
|
|
||||||
//故需要高位清零
|
|
||||||
val hexStr = Integer.toHexString(i and 0xff)
|
|
||||||
//若转换后的十六进制数字只有一位,
|
|
||||||
//则在前补"0"
|
|
||||||
if (hexStr.length == 1) {
|
|
||||||
result.append(0)
|
|
||||||
}
|
|
||||||
result.append(hexStr)
|
|
||||||
}
|
|
||||||
return result.toString()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override fun onBind(intent: Intent): IBinder {
|
override fun onBind(intent: Intent): IBinder {
|
||||||
return mBinder
|
return mBinder
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-6
@@ -1,4 +1,4 @@
|
|||||||
package com.lsp.view.model
|
package com.lsp.view.ui
|
||||||
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
|
||||||
@@ -9,8 +9,4 @@ data class UiState(
|
|||||||
val nowSourceName: MutableLiveData<String> = MutableLiveData(),
|
val nowSourceName: MutableLiveData<String> = MutableLiveData(),
|
||||||
val isSafe: Boolean = true, //安全模式
|
val isSafe: Boolean = true, //安全模式
|
||||||
var nowPage:Int = 1,
|
var nowPage:Int = 1,
|
||||||
){
|
)
|
||||||
fun switchShowSearchBar(){
|
|
||||||
showSearchBar = !showSearchBar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
package com.lsp.view.util
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.content.pm.ResolveInfo
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import android.os.Message
|
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.core.content.FileProvider
|
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import com.lsp.view.R
|
|
||||||
import com.lsp.view.YandViewApplication
|
|
||||||
import java.io.File
|
|
||||||
import kotlin.concurrent.thread
|
|
||||||
|
|
||||||
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){
|
|
||||||
thread {
|
|
||||||
val bitmap = Glide.with(context).asBitmap().load(url).submit().get()
|
|
||||||
val path = File("${context.cacheDir}/image")
|
|
||||||
|
|
||||||
if (!path.exists())
|
|
||||||
path.mkdirs()
|
|
||||||
|
|
||||||
val file = File("${context.cacheDir}/image/cache.png")
|
|
||||||
if (file.exists()){
|
|
||||||
file.delete()
|
|
||||||
}
|
|
||||||
|
|
||||||
file.outputStream().apply {
|
|
||||||
bitmap.compress(Bitmap.CompressFormat.PNG,100,this)
|
|
||||||
}
|
|
||||||
|
|
||||||
val imageUri = FileProvider.getUriForFile(
|
|
||||||
context,
|
|
||||||
"com.lsp.view.fileprovider",
|
|
||||||
file
|
|
||||||
)
|
|
||||||
|
|
||||||
context.grantUriPermission("com.lsp.view",imageUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
|
||||||
|
|
||||||
val shareIntent = Intent(Intent.ACTION_SEND)
|
|
||||||
shareIntent.type = "image/*"
|
|
||||||
shareIntent.putExtra(Intent.EXTRA_STREAM,imageUri)
|
|
||||||
|
|
||||||
val intent = Intent.createChooser(shareIntent,R.string.title_share.toString())
|
|
||||||
val resInfoList:List<ResolveInfo> = if (Build.VERSION.SDK_INT<33) {
|
|
||||||
context.packageManager
|
|
||||||
.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
|
|
||||||
}else{
|
|
||||||
context.packageManager.queryIntentActivities(intent,PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong()))
|
|
||||||
}
|
|
||||||
|
|
||||||
for (resolveInfo in resInfoList) {
|
|
||||||
val packageName = resolveInfo.activityInfo.packageName
|
|
||||||
context.grantUriPermission(
|
|
||||||
packageName,
|
|
||||||
imageUri,
|
|
||||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
context.startActivity(intent)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun download(file_url: String?, file_ext: String?,md5: String?){
|
|
||||||
Toast.makeText(YandViewApplication.context, R.string.toast_download_start, Toast.LENGTH_SHORT).show()
|
|
||||||
|
|
||||||
if (file_url != null) {
|
|
||||||
if (file_ext != null) {
|
|
||||||
YandViewApplication.downloadBinder?.downloadPic(file_url, file_ext,handler,md5)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val handler = object : Handler(Looper.myLooper()!!){
|
|
||||||
override fun handleMessage(msg: Message) {
|
|
||||||
super.handleMessage(msg)
|
|
||||||
when(msg.obj){
|
|
||||||
DOWNLOAD_SUCCESS ->{
|
|
||||||
Toast.makeText(YandViewApplication.context, R.string.toast_download_success, Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
DOWNLOAD_ERROR -> {
|
|
||||||
Toast.makeText(YandViewApplication.context, R.string.toast_download_fail, Toast.LENGTH_SHORT).show()
|
|
||||||
|
|
||||||
}
|
|
||||||
MD5_COMPARE_ERROR -> {
|
|
||||||
Toast.makeText(YandViewApplication.context, R.string.toast_compar_md5_fail, Toast.LENGTH_SHORT).show()
|
|
||||||
|
|
||||||
}
|
|
||||||
FILE_EXISTS -> {
|
|
||||||
Toast.makeText(YandViewApplication.context, R.string.toast_file_exist, Toast.LENGTH_SHORT).show()
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<translate android:fromYDelta="100%p" android:toYDelta="0%p"
|
||||||
|
android:duration="400"/>
|
||||||
|
</set>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<translate android:fromYDelta="0%p" android:toYDelta="100%p"
|
||||||
|
android:duration="400"/>
|
||||||
|
</set>
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
<vector android:height="24dp" android:tint="?attr/colorPrimary"
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
<path android:fillColor="@android:color/white" android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
|
||||||
</vector>
|
</vector>
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<solid android:color="#fff"/>
|
|
||||||
<corners android:radius="5dp"/>
|
|
||||||
|
|
||||||
</shape>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<vector android:autoMirrored="true" android:height="24dp"
|
|
||||||
android:tint="?attr/colorPrimary" android:viewportHeight="24"
|
|
||||||
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24"
|
|
||||||
android:tint="?attr/colorControlNormal">
|
|
||||||
<path
|
|
||||||
android:fillColor="@android:color/white"
|
|
||||||
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
<vector android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"/>
|
<path android:fillColor="@android:color/white" android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"/>
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M17.63,5.84C17.27,5.33 16.67,5 16,5L5,5.01C3.9,5.01 3,5.9 3,7v10c0,1.1 0.9,1.99 2,1.99L16,19c0.67,0 1.27,-0.33 1.63,-0.84L22,12l-4.37,-6.16z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<vector android:height="24dp" android:tint="?attr/colorPrimary"
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z"/>
|
<path android:fillColor="@android:color/white" android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z"/>
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24"
|
|
||||||
android:tint="?attr/colorControlNormal">
|
|
||||||
<path
|
|
||||||
android:fillColor="@android:color/white"
|
|
||||||
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M16.5,3c-1.74,0 -3.41,0.81 -4.5,2.09C10.91,3.81 9.24,3 7.5,3 4.42,3 2,5.42 2,8.5c0,3.78 3.4,6.86 8.55,11.54L12,21.35l1.45,-1.32C18.6,15.36 22,12.28 22,8.5 22,5.42 19.58,3 16.5,3zM12.1,18.55l-0.1,0.1 -0.1,-0.1C7.14,14.24 4,11.39 4,8.5 4,6.5 5.5,5 7.5,5c1.54,0 3.04,0.99 3.57,2.36h1.87C13.46,5.99 14.96,5 16.5,5c2,0 3.5,1.5 3.5,3.5 0,2.89 -3.14,5.74 -7.9,10.05z"/>
|
||||||
|
</vector>
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<solid android:color="?attr/colorAccent"/>
|
|
||||||
<corners android:radius="5dp"/>
|
|
||||||
<padding android:left="10dp"
|
|
||||||
android:right="10dp"
|
|
||||||
android:top="10dp"
|
|
||||||
android:bottom="10dp"/>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</shape>
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.2 KiB |
@@ -1,13 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<solid android:color="?attr/colorPrimary"/>
|
|
||||||
<corners android:radius="5dp"/>
|
|
||||||
<padding android:left="10dp"
|
|
||||||
android:right="10dp"
|
|
||||||
android:top="10dp"
|
|
||||||
android:bottom="10dp"/>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</shape>
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:context=".activity.favtag.FavTagActivity"
|
|
||||||
android:orientation="vertical">
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
|
||||||
android:fitsSystemWindows="true"
|
|
||||||
android:id="@+id/appbar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="?attr/actionBarSize">
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="?attr/actionBarSize"
|
|
||||||
android:id="@+id/toolbar"
|
|
||||||
app:title="@string/title_activity_favouriteTag"
|
|
||||||
/>
|
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:id="@+id/tag_recy"/>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -5,41 +5,27 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".activity.main.MainActivity">
|
tools:context=".activity.MainActivity">
|
||||||
|
|
||||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
<androidx.fragment.app.FragmentContainerView
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
android:id="@+id/nav_host_fragment"
|
||||||
android:id="@+id/swipeRefreshLayout"
|
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/recyclerview"/>
|
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
|
||||||
android:id="@+id/app_bar"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="match_parent"
|
||||||
<com.google.android.material.search.SearchBar
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
android:id="@+id/search_bar"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
android:layout_width="match_parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
android:layout_height="wrap_content" />
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
app:defaultNavHost="true"
|
||||||
|
app:navGraph="@navigation/nav_graph" />
|
||||||
|
|
||||||
<com.google.android.material.search.SearchView
|
|
||||||
android:id="@+id/search_view"
|
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:id="@+id/bottom_navigation"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_anchor="@id/search_bar">
|
app:menu="@menu/nav_menu" />
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/search_tip"
|
|
||||||
android:visibility="gone"/>
|
|
||||||
</com.google.android.material.search.SearchView>
|
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -1,165 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<FrameLayout android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android" >
|
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:fitsSystemWindows="true"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:context=".activity.pic.PicActivity">
|
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:fitsSystemWindows="true"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?android:colorBackground"
|
|
||||||
android:id="@+id/appbar">
|
|
||||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
|
||||||
android:id="@+id/ctl"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:fitsSystemWindows="true"
|
|
||||||
app:layout_scrollFlags="scroll|exitUntilCollapsed">
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="?attr/actionBarSize"
|
|
||||||
android:id="@+id/toolbar"/>
|
|
||||||
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
app:layout_collapseMode="parallax"
|
|
||||||
android:fitsSystemWindows="true"
|
|
||||||
android:id="@+id/titleImage"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:scaleType="centerCrop"
|
|
||||||
android:contentDescription="@string/appbar_scrolling_view_behavior"/>
|
|
||||||
|
|
||||||
|
|
||||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
|
||||||
style="?attr/materialCardViewStyle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="15dp"
|
|
||||||
android:layout_marginLeft="15dp"
|
|
||||||
android:layout_marginRight="15dp"
|
|
||||||
android:layout_marginTop="5dp"
|
|
||||||
app:cardCornerRadius="10dp">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:layout_marginStart="5dp"
|
|
||||||
android:layout_marginBottom="10dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/idRecyclerView"/>
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:layout_marginStart="5dp"
|
|
||||||
android:layout_marginBottom="10dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/tagRecyclerView"/>
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:layout_marginStart="5dp"
|
|
||||||
android:layout_marginBottom="10dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/authorRecyclerView"/>
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:layout_marginStart="5dp"
|
|
||||||
android:layout_marginBottom="10dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/sizeRecyclerView"/>
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/float_line"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:layout_margin="15dp"
|
|
||||||
android:layout_gravity="end|bottom"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
<LinearLayout
|
|
||||||
android:visibility="gone"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/ctrl"
|
|
||||||
android:orientation="vertical">
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:elevation="5dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="10dp"
|
|
||||||
android:src="@drawable/ic_twotone_arrow_downward_24"
|
|
||||||
android:id="@+id/download"/>
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:elevation="5dp"
|
|
||||||
android:layout_margin="10dp"
|
|
||||||
android:src="@drawable/ic_twotone_share_24"
|
|
||||||
android:id="@+id/share"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
||||||
android:layout_width="80dp"
|
|
||||||
android:layout_height="80dp"
|
|
||||||
app:fabCustomSize="80dp"
|
|
||||||
android:layout_margin="10dp"
|
|
||||||
android:src="@drawable/ic_baseline_add_24"
|
|
||||||
android:elevation="5dp"
|
|
||||||
android:id="@+id/float_btn"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
||||||
|
|
||||||
<com.github.chrisbanes.photoview.PhotoView
|
|
||||||
android:background="#000"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:id="@+id/photoView"/>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_margin="30dp"
|
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
android:id="@+id/back"
|
|
||||||
android:src="@drawable/ic_baseline_arrow_back_24"
|
|
||||||
android:layout_gravity="top|start"
|
|
||||||
/>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
|
||||||
style="?attr/materialCardViewFilledStyle"
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="wrap_content">
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/fav_tag"
|
|
||||||
android:layout_margin="5dp"
|
|
||||||
android:padding="5dp"
|
|
||||||
android:textSize="20sp"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".fragment.CollectFragment">
|
||||||
|
|
||||||
|
<include layout="@layout/post_list_layout"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
tools:context=".fragment.ImageFragment">
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<com.github.chrisbanes.photoview.PhotoView
|
||||||
|
android:id="@+id/image_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.bottomappbar.BottomAppBar
|
||||||
|
android:id="@+id/bottomAppBar"
|
||||||
|
style="@style/Widget.Material3.BottomAppBar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
app:menu="@menu/image_bottom_menu" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/download_btn"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_anchor="@id/bottomAppBar"
|
||||||
|
app:srcCompat="@drawable/baseline_file_download_24"
|
||||||
|
android:contentDescription="@string/description_download" />
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<include layout="@layout/post_list_layout"/>
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:id="@+id/app_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
<com.google.android.material.search.SearchBar
|
||||||
|
android:id="@+id/search_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.search.SearchView
|
||||||
|
android:id="@+id/search_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_anchor="@id/search_bar">
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/search_tip"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
</com.google.android.material.search.SearchView>
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
android:id="@+id/picImgae"/>
|
android:id="@+id/image"/>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/nav_header"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="30dp">
|
|
||||||
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
android:id="@+id/swipeRefreshLayout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:ignore="MissingConstraints">
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/recyclerview"/>
|
||||||
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@android:id/text1"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ellipsize="marquee"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:textAlignment="inherit"
|
|
||||||
android:textSize="20sp"/>
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
|
||||||
android:id="@+id/card"
|
|
||||||
android:layout_margin="5dp"
|
|
||||||
style="?attr/materialCardViewFilledStyle"
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="wrap_content">
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tag"
|
|
||||||
android:padding="5dp"
|
|
||||||
android:textSize="20sp"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item android:contentDescription="@string/description_share"
|
||||||
|
android:id="@+id/share_menu_btn"
|
||||||
|
android:title="@string/title_share"
|
||||||
|
android:icon="@drawable/ic_twotone_share_24"
|
||||||
|
app:showAsAction="ifRoom"/>
|
||||||
|
<item android:id="@+id/collect_menu_btn"
|
||||||
|
android:title="@string/title_collect"
|
||||||
|
android:icon="@drawable/ic_baseline_favorite_24"
|
||||||
|
app:showAsAction="ifRoom"/>
|
||||||
|
|
||||||
|
</menu>
|
||||||
@@ -2,16 +2,16 @@
|
|||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<group android:checkableBehavior="single">
|
<group android:checkableBehavior="single">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/photo"
|
android:id="@+id/postListFragment"
|
||||||
android:icon="@drawable/ic_baseline_insert_photo_24"
|
android:icon="@drawable/ic_baseline_insert_photo_24"
|
||||||
android:title="@string/item_gallery"/>
|
android:title="@string/item_gallery"/>
|
||||||
<item
|
<item
|
||||||
android:id="@+id/taglist"
|
android:id="@+id/collectFragment"
|
||||||
android:icon="@drawable/ic_baseline_label_24"
|
android:icon="@drawable/ic_baseline_favorite_24"
|
||||||
android:title="@string/item_collect"/>
|
android:title="@string/item_collect"/>
|
||||||
<item
|
<!-- <item-->
|
||||||
android:id="@+id/setting"
|
<!-- android:id="@+id/setting"-->
|
||||||
android:icon="@drawable/setting_icon"
|
<!-- android:icon="@drawable/setting_icon"-->
|
||||||
android:title="@string/item_settings"/>
|
<!-- android:title="@string/item_settings"/>-->
|
||||||
</group>
|
</group>
|
||||||
</menu>
|
</menu>
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
<item
|
|
||||||
android:id="@+id/search_nav"
|
|
||||||
android:icon="@drawable/ic_baseline_search_24"
|
|
||||||
app:showAsAction="always"
|
|
||||||
android:title="@string/item_search" />
|
|
||||||
|
|
||||||
</menu>
|
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/nav_graph"
|
||||||
|
app:startDestination="@id/postListFragment">
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/postListFragment"
|
||||||
|
android:name="com.lsp.view.fragment.PostListFragment"
|
||||||
|
android:label="PostListFragment" >
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_postListFragment_to_imageFragment"
|
||||||
|
app:destination="@id/imageFragment"
|
||||||
|
app:enterAnim="@anim/slide_on_bottom"
|
||||||
|
app:exitAnim="@anim/nav_default_exit_anim"
|
||||||
|
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||||
|
app:popExitAnim="@anim/slide_out_bottom" >
|
||||||
|
</action>
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_postListFragment_to_collectFragment"
|
||||||
|
app:destination="@id/collectFragment" />
|
||||||
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/imageFragment"
|
||||||
|
android:name="com.lsp.view.fragment.ImageFragment"
|
||||||
|
android:label="fragment_pic"
|
||||||
|
tools:layout="@layout/fragment_image" >
|
||||||
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/collectFragment"
|
||||||
|
android:name="com.lsp.view.fragment.CollectFragment"
|
||||||
|
android:label="fragment_collect"
|
||||||
|
tools:layout="@layout/fragment_collect" >
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_collectFragment_to_imageFragment"
|
||||||
|
app:destination="@id/imageFragment"
|
||||||
|
app:enterAnim="@anim/slide_on_bottom"
|
||||||
|
app:exitAnim="@anim/nav_default_exit_anim"
|
||||||
|
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||||
|
app:popExitAnim="@anim/slide_out_bottom"/>
|
||||||
|
</fragment>
|
||||||
|
</navigation>
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="title_activity_settings">设置</string>
|
<string name="title_activity_settings">设置</string>
|
||||||
<string name="title_activity_favouriteTag">收藏标签</string>
|
|
||||||
<string name="item_gallery">画廊</string>
|
<string name="item_gallery">画廊</string>
|
||||||
<string name="item_collect">收藏</string>
|
<string name="item_collect">收藏</string>
|
||||||
<string name="item_settings">设置</string>
|
<string name="item_settings">设置</string>
|
||||||
@@ -24,8 +23,8 @@
|
|||||||
<string name="toast_tag_exist">收藏过了哦</string>
|
<string name="toast_tag_exist">收藏过了哦</string>
|
||||||
<string name="toast_download_success">下载成功</string>
|
<string name="toast_download_success">下载成功</string>
|
||||||
<string name="toast_download_fail">下载失败</string>
|
<string name="toast_download_fail">下载失败</string>
|
||||||
<string name="toast_compar_md5_fail">MD5对比失败</string>
|
|
||||||
<string name="toast_file_exist">文件已经存在</string>
|
<string name="toast_file_exist">文件已经存在</string>
|
||||||
<string name="toast_download_start">开始下载</string>
|
<string name="toast_download_start">开始下载</string>
|
||||||
<string name="title_share">分享</string>
|
<string name="title_share">分享</string>
|
||||||
|
<string name="title_collect">收藏</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
<string name="app_name" translatable="false">YandView</string>
|
<string name="app_name" translatable="false">YandView</string>
|
||||||
<string name="title_activity_settings">SettingsActivity</string>
|
<string name="title_activity_settings">SettingsActivity</string>
|
||||||
<string name="title_activity_settings_backup" translatable="false">SettingsActivity_backup</string>
|
<string name="title_activity_settings_backup" translatable="false">SettingsActivity_backup</string>
|
||||||
<string name="title_activity_favouriteTag">FavouriteTag</string>
|
|
||||||
<string name="item_gallery">Gallery</string>
|
<string name="item_gallery">Gallery</string>
|
||||||
<string name="item_collect">Collect</string>
|
<string name="item_collect">Collect</string>
|
||||||
<string name="item_settings">Settings</string>
|
<string name="item_settings">Settings</string>
|
||||||
@@ -25,8 +24,8 @@
|
|||||||
<string name="toast_tag_exist">This tag exist</string>
|
<string name="toast_tag_exist">This tag exist</string>
|
||||||
<string name="toast_download_success">Successfully download</string>
|
<string name="toast_download_success">Successfully download</string>
|
||||||
<string name="toast_download_fail">Download failed</string>
|
<string name="toast_download_fail">Download failed</string>
|
||||||
<string name="toast_compar_md5_fail">MD5 comparison failed</string>
|
|
||||||
<string name="toast_file_exist">File exists</string>
|
<string name="toast_file_exist">File exists</string>
|
||||||
<string name="toast_download_start">Start download</string>
|
<string name="toast_download_start">Start download</string>
|
||||||
<string name="title_share">Share</string>
|
<string name="title_share">Share</string>
|
||||||
|
<string name="title_collect">Collect</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -8,12 +8,17 @@ buildscript {
|
|||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:8.1.1'
|
classpath 'com.android.tools.build:gradle:8.1.1'
|
||||||
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10'
|
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10'
|
||||||
|
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.7.5"
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'com.google.devtools.ksp' version '1.9.20-1.0.14' apply false
|
||||||
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
maven { url "https://www.jitpack.io" }
|
maven { url "https://www.jitpack.io" }
|
||||||
|
|||||||
Reference in New Issue
Block a user