Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ec6305d00a | |||
| 25046d22a8 | |||
| bbd4c3b7d1 | |||
| d2c903ca41 | |||
| 816eaa7ecf | |||
| 1c48892cb4 | |||
| 0637278a17 | |||
| 415139d67d | |||
| c13215a6dd | |||
| c82509b320 | |||
| ad5ef05c60 | |||
| 8736940b9f | |||
| e925b14b47 | |||
| f28d36f0f4 | |||
| 3998658726 | |||
| 0c9c3958fb | |||
| 7a3b7947fb | |||
| 58f39bd610 | |||
| fe605d0f89 | |||
| 1870bc71c3 | |||
| 3756900873 |
@@ -19,3 +19,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
test
|
||||
+5
-4
@@ -8,7 +8,7 @@ android {
|
||||
buildToolsVersion "30.0.3"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.lsper.view"
|
||||
applicationId "com.lsp.view"
|
||||
minSdkVersion 29
|
||||
targetSdkVersion 33
|
||||
versionCode 221022
|
||||
@@ -24,12 +24,13 @@ android {
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
namespace 'com.lsp.view'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -45,7 +46,7 @@ dependencies {
|
||||
implementation 'androidx.preference:preference-ktx:1.2.0'
|
||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
implementation 'androidx.core:core-ktx:1.7.0'
|
||||
implementation 'androidx.core:core-ktx:1.9.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.lsp.view">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
@@ -15,7 +14,7 @@
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="com.lsper.view.fileprovider"
|
||||
android:authorities="com.lsp.view.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
@@ -37,7 +36,6 @@
|
||||
android:enabled="true"
|
||||
android:exported="true" />
|
||||
|
||||
<activity android:name=".activity.login.LoginActivity" />
|
||||
<activity
|
||||
android:name=".activity.pic.PicActivity"
|
||||
android:configChanges="uiMode"/>
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.google.android.material.color.DynamicColors
|
||||
import android.content.Intent
|
||||
import com.lsp.view.service.DownloadService
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.lsp.view.repository.PostRepository
|
||||
|
||||
class YandViewApplication : Application(), DefaultLifecycleObserver {
|
||||
private val connection: ServiceConnection = object : ServiceConnection {
|
||||
@@ -20,6 +21,7 @@ class YandViewApplication : Application(), DefaultLifecycleObserver {
|
||||
|
||||
override fun onServiceDisconnected(componentName: ComponentName) {}
|
||||
}
|
||||
val repository = PostRepository()
|
||||
|
||||
override fun onCreate() {
|
||||
super<Application>.onCreate()
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.os.Bundle
|
||||
import android.view.WindowManager
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
|
||||
open class BaseActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -25,8 +26,8 @@ open class BaseActivity : AppCompatActivity() {
|
||||
window.statusBarColor = Color.TRANSPARENT
|
||||
window.navigationBarColor = Color.TRANSPARENT
|
||||
//状态栏反色
|
||||
val controller = ViewCompat.getWindowInsetsController(window.decorView)
|
||||
controller?.isAppearanceLightStatusBars = !isDarkMode()
|
||||
WindowCompat.getInsetsController(window,window.decorView).isAppearanceLightStatusBars = !isDarkMode()
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,7 +15,7 @@ import com.lsp.view.YandViewApplication
|
||||
import com.lsp.view.R
|
||||
import com.lsp.view.activity.BaseActivity
|
||||
import com.lsp.view.activity.main.MainActivity
|
||||
import com.lsp.view.bean.Tags
|
||||
import com.lsp.view.repository.bean.Tags
|
||||
|
||||
class FavTagActivity : BaseActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
@@ -9,7 +9,7 @@ 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.bean.Tags
|
||||
import com.lsp.view.repository.bean.Tags
|
||||
|
||||
class FavTagAdapter(val tagList: ArrayList<Tags>, val context: Context) :
|
||||
RecyclerView.Adapter<FavTagAdapter.ViewHolder>() {
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
package com.lsp.view.activity.login
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.widget.EditText
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.lsp.view.R
|
||||
import com.lsp.view.activity.main.MainActivity
|
||||
import okhttp3.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class LoginActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_login)
|
||||
val login = findViewById<FloatingActionButton>(R.id.login)
|
||||
|
||||
|
||||
login.setOnClickListener {
|
||||
val username = findViewById<EditText>(R.id.username)
|
||||
val password = findViewById<EditText>(R.id.password)
|
||||
val sPassword = "choujin-steiner--${password.text}--"
|
||||
val hash1Password = StrToHash1.shaEncrypt(sPassword)
|
||||
thread {
|
||||
conn(username.text.toString(), hash1Password)
|
||||
}
|
||||
val intent = Intent(this, MainActivity::class.java)
|
||||
startActivity(intent)
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
fun conn(username: String, hash1: String): String {
|
||||
val cookies = ArrayList<Cookie>()
|
||||
val client = OkHttpClient.Builder()
|
||||
.connectTimeout(60, TimeUnit.SECONDS)
|
||||
.cookieJar(object : CookieJar {
|
||||
override fun saveFromResponse(url: HttpUrl, cookies: MutableList<Cookie>) {
|
||||
}
|
||||
|
||||
override fun loadForRequest(url: HttpUrl): MutableList<Cookie> {
|
||||
return cookies
|
||||
}
|
||||
|
||||
})
|
||||
.build()
|
||||
val request = Request.Builder()
|
||||
.url("https://yande.re/?username=$username&password=$hash1")
|
||||
.build()
|
||||
return client.newCall(request).execute().body()!!.string()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package com.lsp.view.activity.login;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public class StrToHash1 {
|
||||
public static String shaEncrypt(String strSrc) {
|
||||
MessageDigest md = null;
|
||||
String strDes = null;
|
||||
byte[] bt = strSrc.getBytes();
|
||||
try {
|
||||
md = MessageDigest.getInstance("SHA-1");
|
||||
md.update(bt);
|
||||
strDes = bytes2Hex(md.digest());
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return null;
|
||||
}
|
||||
return strDes;
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static String bytes2Hex(byte[] bts) {
|
||||
StringBuilder des = new StringBuilder();
|
||||
String tmp = null;
|
||||
for (byte bt : bts) {
|
||||
tmp = Integer.toHexString(bt & 0xFF);
|
||||
if (tmp.length() == 1) {
|
||||
des.append("0");
|
||||
}
|
||||
des.append(tmp);
|
||||
}
|
||||
return des.toString();
|
||||
}
|
||||
}
|
||||
@@ -4,146 +4,96 @@ import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.content.Intent
|
||||
import android.os.*
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat.Type.ime
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.lsp.view.YandViewApplication
|
||||
import com.lsp.view.R
|
||||
import com.lsp.view.activity.BaseActivity
|
||||
import com.lsp.view.activity.favtag.FavTagActivity
|
||||
import com.lsp.view.activity.model.MainActivityModelImpl
|
||||
import com.lsp.view.activity.setting.SettingsActivity
|
||||
import com.lsp.view.bean.Post_yand
|
||||
import com.lsp.view.util.CallBackStatus
|
||||
import com.lsp.view.model.MainViewModel
|
||||
|
||||
|
||||
class MainActivity : BaseActivity() {
|
||||
private var searchTag: String? = null
|
||||
private lateinit var search: EditText
|
||||
private lateinit var searchBar: LinearLayout
|
||||
private var shortAnnotationDuration: Int = 0
|
||||
private var nowPage = 1
|
||||
private val adapter: PostAdapter = PostAdapter(this, ArrayList())
|
||||
private var username: String? = ""
|
||||
private lateinit var sourceUrlArray: Array<String>
|
||||
private lateinit var sourceNameArray: Array<String>
|
||||
private var nowSourceName: String? = null
|
||||
val TAG = javaClass.simpleName
|
||||
private lateinit var layoutManager: RecyclerView.LayoutManager
|
||||
private var safeMode: Boolean = true //安全模式
|
||||
private lateinit var recyclerView: RecyclerView
|
||||
private var barShow = false
|
||||
private var tags: String? = ""
|
||||
private val ISREFRESH = 1
|
||||
private val ISADDDATA = 0
|
||||
private lateinit var toolbar:Toolbar
|
||||
private lateinit var viewModel: MainViewModel
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
|
||||
val toolbar = findViewById<Toolbar>(R.id.toolbar)
|
||||
viewModel = MainViewModel.provideFactory((application as YandViewApplication).repository, this,this).create(MainViewModel::class.java)
|
||||
|
||||
toolbar = findViewById(R.id.toolbar)
|
||||
setSupportActionBar(toolbar)
|
||||
val appbar = findViewById<AppBarLayout>(R.id.appbar)
|
||||
val nowHeight = appbar.layoutParams.height
|
||||
appbar.layoutParams.height = (application as YandViewApplication).statusBarHeight()+nowHeight
|
||||
supportActionBar?.setDisplayShowTitleEnabled(false)
|
||||
//刷新
|
||||
val refresh =
|
||||
findViewById<androidx.swiperefreshlayout.widget.SwipeRefreshLayout>(R.id.swipeRefreshLayout)
|
||||
|
||||
//到达底部,加载更多数据
|
||||
adapter.setLoadMoreListener(object : PostAdapter.OnLoadMoreListener {
|
||||
//重写接口
|
||||
override fun loadMore(position: Int) {
|
||||
loadData(tags,++nowPage,ISADDDATA)
|
||||
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
//初始化数据
|
||||
sourceNameArray = resources.getStringArray(R.array.pic_source)
|
||||
sourceUrlArray = resources.getStringArray(R.array.url_source)
|
||||
val configSp = getSharedPreferences("com.lsper.view_preferences", 0)
|
||||
if (configSp.getString("sourceName", null) == null) {
|
||||
configSp.edit().putString("sourceName", "yande.re").apply()
|
||||
configSp.edit().putString("type", "0").apply()
|
||||
viewModel.uiState.value.isRefreshing.observe(this) {
|
||||
refresh.isRefreshing = it
|
||||
}
|
||||
nowSourceName = configSp.getString("sourceName","yande.re")
|
||||
safeMode = configSp.getBoolean("safe_mode",true)
|
||||
|
||||
refresh.setOnRefreshListener {
|
||||
viewModel.fetchPostByRefresh()
|
||||
}
|
||||
|
||||
viewModel.adapter.apply {
|
||||
setLoadMoreListener(object :PostAdapter.OnScrollToBottom{
|
||||
override fun event(position: Int) {
|
||||
viewModel.appendPost()
|
||||
}
|
||||
|
||||
//横屏逻辑
|
||||
layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
|
||||
recyclerView = findViewById(R.id.recyclerview)
|
||||
|
||||
recyclerView.layoutManager = layoutManager
|
||||
recyclerView.adapter = adapter
|
||||
|
||||
|
||||
|
||||
//收藏Tag
|
||||
val swipeRefreshLayout =
|
||||
findViewById<androidx.swiperefreshlayout.widget.SwipeRefreshLayout>(
|
||||
R.id.swipeRefreshLayout
|
||||
)
|
||||
val drawerLayout = findViewById<DrawerLayout>(R.id.drawerLayout)
|
||||
})
|
||||
}
|
||||
|
||||
findViewById<RecyclerView>(R.id.recyclerview).apply {
|
||||
val layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
|
||||
this.layoutManager = layoutManager
|
||||
this.adapter = viewModel.adapter
|
||||
}
|
||||
|
||||
search = findViewById(R.id.search)
|
||||
//快捷搜索tag 来自PicActivity
|
||||
searchTag = intent.getStringExtra("searchTag")
|
||||
if (searchTag != null) {
|
||||
//tag按钮搜索
|
||||
this.search.setText(searchTag)
|
||||
searchAction(searchTag)
|
||||
} else {
|
||||
//初次启动
|
||||
loadData( tags,1,ISADDDATA)
|
||||
}
|
||||
|
||||
val close = findViewById<View>(R.id.close)
|
||||
|
||||
supportActionBar?.let {
|
||||
it.setDisplayHomeAsUpEnabled(true)
|
||||
it.setHomeAsUpIndicator(R.drawable.ic_baseline_menu_24)
|
||||
}
|
||||
|
||||
searchBar = findViewById(R.id.search_bar)
|
||||
shortAnnotationDuration = resources.getInteger(android.R.integer.config_shortAnimTime)
|
||||
close.setOnClickListener {
|
||||
hiddenSearchBar()
|
||||
hideIm()
|
||||
}
|
||||
|
||||
search.setOnEditorActionListener { v, actionId, event ->
|
||||
search.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
||||
searchAction(search.text.toString())
|
||||
searchTag = search.text.toString()
|
||||
hiddenSearchBar()
|
||||
viewModel.fetchNewPostBySearch(search.text.toString())
|
||||
}
|
||||
return@setOnEditorActionListener false
|
||||
}
|
||||
|
||||
|
||||
//刷新
|
||||
swipeRefreshLayout.setOnRefreshListener {
|
||||
nowPage = 1
|
||||
loadData( searchTag, nowPage, ISREFRESH)
|
||||
}
|
||||
|
||||
//侧边栏
|
||||
val sp = getSharedPreferences("username", 0)
|
||||
@@ -155,12 +105,12 @@ class MainActivity : BaseActivity() {
|
||||
nav.setCheckedItem(R.id.photo)
|
||||
//设置侧边栏点击逻辑
|
||||
nav.setNavigationItemSelectedListener {
|
||||
val drawerLayout = findViewById<DrawerLayout>(R.id.drawerLayout)
|
||||
when (it.itemId) {
|
||||
//画廊
|
||||
R.id.photo -> {
|
||||
loadData( null, 1, ISREFRESH)
|
||||
viewModel.fetchPostByRefresh()
|
||||
drawerLayout.closeDrawers()
|
||||
searchTag = ""
|
||||
true
|
||||
}
|
||||
//设置
|
||||
@@ -186,38 +136,42 @@ class MainActivity : BaseActivity() {
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
//加载源改变
|
||||
val configSp = getSharedPreferences("com.lsper.view_preferences", 0)
|
||||
if (nowSourceName != configSp.getString("sourceName",null)){
|
||||
loadData(tags,1,ISREFRESH)
|
||||
nowSourceName = configSp.getString("sourceName",null)
|
||||
val configSp = getSharedPreferences("com.lsp.view_preferences", 0)
|
||||
if (nowSourceName != configSp.getString("source_name",null)){
|
||||
viewModel.fetchPostByRefresh()
|
||||
nowSourceName = configSp.getString("source_name",null)
|
||||
}
|
||||
|
||||
if (safeMode != configSp.getBoolean("safe_mode",true)){
|
||||
loadData(tags,1,ISREFRESH)
|
||||
viewModel.fetchPostByRefresh()
|
||||
safeMode = configSp.getBoolean("safe_mode",true)
|
||||
}
|
||||
|
||||
search.setText("")
|
||||
|
||||
}
|
||||
|
||||
//隐藏搜索栏
|
||||
private fun hiddenSearchBar() {
|
||||
searchBar.animate()
|
||||
supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_baseline_menu_24)
|
||||
search.animate()
|
||||
.alpha(0f)
|
||||
.setDuration(shortAnnotationDuration.toLong())
|
||||
.setListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
searchBar.visibility = View.GONE
|
||||
search.visibility = View.GONE
|
||||
}
|
||||
})
|
||||
hideIm()
|
||||
barShow = false
|
||||
|
||||
viewModel.uiState.value.switchShowSearchBar()
|
||||
}
|
||||
|
||||
//现实搜索栏
|
||||
private fun showSearchBar() {
|
||||
searchBar.apply {
|
||||
supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_baseline_arrow_back_24)
|
||||
search.apply {
|
||||
alpha = 0f
|
||||
visibility = View.VISIBLE
|
||||
animate()
|
||||
@@ -225,25 +179,27 @@ class MainActivity : BaseActivity() {
|
||||
.setDuration(shortAnnotationDuration.toLong())
|
||||
.setListener(null)
|
||||
}
|
||||
barShow = true
|
||||
viewModel.uiState.value.switchShowSearchBar()
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
val drawerLayout = findViewById<DrawerLayout>(R.id.drawerLayout)
|
||||
drawerLayout.openDrawer(GravityCompat.START)
|
||||
if (viewModel.uiState.value.showSearchBar){
|
||||
hiddenSearchBar()
|
||||
}else {
|
||||
val drawerLayout = findViewById<DrawerLayout>(R.id.drawerLayout)
|
||||
drawerLayout.openDrawer(GravityCompat.START)
|
||||
}
|
||||
}
|
||||
R.id.search_nav -> {
|
||||
if (barShow) {
|
||||
searchTag = search.text.toString()
|
||||
searchAction(searchTag)
|
||||
hiddenSearchBar()
|
||||
|
||||
if (viewModel.uiState.value.showSearchBar) {
|
||||
viewModel.fetchNewPostBySearch(search.text.toString())
|
||||
hideIm()
|
||||
|
||||
}
|
||||
|
||||
if (searchBar.visibility == View.GONE) {
|
||||
if (search.visibility == View.GONE) {
|
||||
showSearchBar()
|
||||
}
|
||||
}
|
||||
@@ -253,82 +209,9 @@ class MainActivity : BaseActivity() {
|
||||
|
||||
|
||||
private fun hideIm() {
|
||||
val controller = ViewCompat.getWindowInsetsController(window.decorView)
|
||||
controller?.hide(ime())
|
||||
WindowCompat.getInsetsController(this.window,window.decorView).hide(ime())
|
||||
}
|
||||
|
||||
//执行搜索
|
||||
private fun searchAction(tags: String?) {
|
||||
var tag = tags
|
||||
var isNum = true
|
||||
try {
|
||||
tags?.toInt()
|
||||
}catch (e:NumberFormatException){
|
||||
isNum = false
|
||||
}
|
||||
|
||||
if (isNum){
|
||||
tag = "id:"+tags
|
||||
}
|
||||
|
||||
loadData(tag, 1, ISREFRESH)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
//设置列表数据
|
||||
private fun loadData(tags: String?,page: Int,type:Int){
|
||||
//缓存搜索的tags
|
||||
this.tags = tags
|
||||
|
||||
val swipeRefreshLayout =
|
||||
findViewById<androidx.swiperefreshlayout.widget.SwipeRefreshLayout>(
|
||||
R.id.swipeRefreshLayout
|
||||
)
|
||||
swipeRefreshLayout.isRefreshing = true
|
||||
|
||||
//读取配置
|
||||
val configSp = getSharedPreferences("com.lsper.view_preferences", 0)
|
||||
val nowSourceName: String? = configSp.getString("sourceName",null)
|
||||
var source = ""
|
||||
for ((index,sourceName) in sourceNameArray.withIndex()){
|
||||
if (sourceName == nowSourceName){
|
||||
source = sourceUrlArray[index]
|
||||
}
|
||||
}
|
||||
|
||||
//接收异步信息
|
||||
val handler = object : Handler(Looper.myLooper()!!){
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when (msg.what){
|
||||
CallBackStatus.DATAISNULL.ordinal ->{
|
||||
Snackbar.make(swipeRefreshLayout,R.string.toast_load_empty,Snackbar.LENGTH_SHORT).show()
|
||||
search.setText("")
|
||||
}
|
||||
CallBackStatus.OK.ordinal -> {
|
||||
if (type == ISREFRESH )
|
||||
//刷新数据
|
||||
adapter.refreshData(msg.obj as ArrayList<Post_yand>)
|
||||
else if (type == ISADDDATA)
|
||||
//加载数据
|
||||
adapter.addData(msg.obj as ArrayList<Post_yand>)
|
||||
|
||||
}
|
||||
CallBackStatus.NETWORKERROR.ordinal -> {
|
||||
Snackbar.make(swipeRefreshLayout,R.string.toast_load_network_fail,Snackbar.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
swipeRefreshLayout.isRefreshing = false
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
MainActivityModelImpl().requestPostList(handler,source,tags,page,configSp.getBoolean("safe_mode",true))
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
menuInflater.inflate(R.menu.toolbar_menu, menu)
|
||||
|
||||
@@ -1,92 +1,105 @@
|
||||
package com.lsp.view.activity.main
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.model.GlideUrl
|
||||
import com.bumptech.glide.load.model.LazyHeaders
|
||||
import com.lsp.view.R
|
||||
import com.lsp.view.activity.pic.PicActivity
|
||||
import com.lsp.view.bean.Post_yand
|
||||
import com.lsp.view.repository.bean.YandPost
|
||||
|
||||
|
||||
class PostAdapter(val context: Context, private var postYandList: ArrayList<Post_yand>) :
|
||||
class PostAdapter(val context: Context):
|
||||
RecyclerView.Adapter<PostAdapter.ViewHolder>() {
|
||||
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 postList = ArrayList<YandPost>()
|
||||
|
||||
|
||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val picImage: ImageView = view.findViewById(R.id.picImgae)
|
||||
|
||||
}
|
||||
|
||||
fun addData(list: ArrayList<Post_yand>) {
|
||||
val pos = postYandList.size
|
||||
postYandList.addAll(list)
|
||||
notifyItemRangeInserted(pos, list.size)
|
||||
fun pushNewData(list: ArrayList<YandPost>) {
|
||||
val oldSize = postList.size
|
||||
postList.clear()
|
||||
notifyItemRangeRemoved(0,oldSize)
|
||||
postList.addAll(list)
|
||||
notifyItemRangeInserted(0, list.size)
|
||||
}
|
||||
|
||||
fun refreshData(list: ArrayList<Post_yand>) {
|
||||
|
||||
val oldSize = postYandList.size
|
||||
postYandList.clear()
|
||||
notifyItemRangeRemoved(0,oldSize)
|
||||
postYandList.addAll(list)
|
||||
notifyItemRangeInserted(0, list.size)
|
||||
fun appendDate(list: ArrayList<YandPost>){
|
||||
val pos = postList.size
|
||||
postList.addAll(list)
|
||||
notifyItemRangeInserted(pos, list.size)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val view = LayoutInflater.from(context).inflate(R.layout.img_item_layout, parent, false)
|
||||
val viewHolder = ViewHolder(view)
|
||||
|
||||
viewHolder.picImage.setOnClickListener {
|
||||
val position = viewHolder.adapterPosition
|
||||
Log.w("position", position.toString())
|
||||
Log.w("url", postYandList[position].sample_url)
|
||||
Log.w("rating", postYandList[position].rating)
|
||||
var file_ext = postYandList[position].file_ext
|
||||
// Log.w("position", position.toString())
|
||||
// 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 = postYandList[position].sample_url.split(".")
|
||||
val strarr = postList[position].sample_url.split(".")
|
||||
file_ext = strarr[strarr.lastIndex]
|
||||
}
|
||||
|
||||
PicActivity.actionStartActivity(context,postYandList[position].id,postYandList[position].sample_url,
|
||||
postYandList[position].file_url,postYandList[position].tags,file_ext,
|
||||
postYandList[position].author,postYandList[position].file_size,postYandList[position].md5)
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
return viewHolder
|
||||
}
|
||||
|
||||
private lateinit var mLoadMoreListener: OnLoadMoreListener
|
||||
private lateinit var mScrollToBottom: OnScrollToBottom
|
||||
|
||||
interface OnLoadMoreListener {
|
||||
fun loadMore(position: Int)
|
||||
interface OnScrollToBottom {
|
||||
fun event(position: Int)
|
||||
}
|
||||
|
||||
fun setLoadMoreListener(mLoadMoreListener: OnLoadMoreListener) {
|
||||
this.mLoadMoreListener = mLoadMoreListener
|
||||
|
||||
fun setLoadMoreListener(mLoadMoreListener: OnScrollToBottom) {
|
||||
this.mScrollToBottom = mLoadMoreListener
|
||||
}
|
||||
|
||||
private fun preLoad(p:Int){
|
||||
if (p%20==0){
|
||||
//执行预加载
|
||||
val last:Int = if (postYandList.size-p<20){
|
||||
postYandList.size-1
|
||||
val last:Int = if (postList.size-p<20){
|
||||
postList.size-1
|
||||
}else{
|
||||
p+19
|
||||
}
|
||||
for(index in p..last){
|
||||
if (p>6) {
|
||||
val source: String = postYandList[index].sample_url
|
||||
val source: String = postList[index].sample_url
|
||||
val glideUrl = GlideUrl(
|
||||
source,
|
||||
LazyHeaders.Builder().addHeader("User-Agent", UA)
|
||||
@@ -96,21 +109,22 @@ class PostAdapter(val context: Context, private var postYandList: ArrayList<Post
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
|
||||
preLoad(position)
|
||||
|
||||
val post = postYandList[position]
|
||||
val post = postList[position]
|
||||
|
||||
val source: String = post.sample_url
|
||||
|
||||
val height = postYandList[position].sample_height
|
||||
val width = postYandList[position].sample_width
|
||||
val height = postList[position].sample_height
|
||||
val width = postList[position].sample_width
|
||||
|
||||
//图片过长则缩减高度以保证显示完整
|
||||
if (width*0.75 > height){
|
||||
if (width > height){
|
||||
holder.picImage.layoutParams.height = height / 2
|
||||
}else {
|
||||
holder.picImage.layoutParams.height = height
|
||||
@@ -124,15 +138,17 @@ class PostAdapter(val context: Context, private var postYandList: ArrayList<Post
|
||||
)
|
||||
Glide.with(context).load(glideUrl).into(holder.picImage)
|
||||
|
||||
if (position == postYandList.size - 1 && postYandList.size > 6) {
|
||||
if (position == postList.size - 1 && postList.size > 6) {
|
||||
//到达底部
|
||||
mLoadMoreListener.loadMore(position)
|
||||
mScrollToBottom.event(position)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return postYandList.size
|
||||
val size = postList.size
|
||||
return size
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.lsp.view.activity.model
|
||||
|
||||
import android.os.Handler
|
||||
|
||||
interface MainActivityModel {
|
||||
fun requestPostList(handler: Handler, source: String, tage: String?, page: Int, safeMode: Boolean)
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package com.lsp.view.activity.model
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Message
|
||||
import com.lsp.view.retrofit.PostService
|
||||
import com.lsp.view.retrofit.ServiceCreator
|
||||
import com.lsp.view.bean.Post
|
||||
import com.lsp.view.bean.Post_yand
|
||||
import com.lsp.view.util.CallBackStatus
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class MainActivityModelImpl :MainActivityModel {
|
||||
private val TAG = this::class.java.simpleName
|
||||
override fun requestPostList(handler: Handler, source: String, tage: String?, page: Int,safeMode: Boolean){
|
||||
val postService: PostService = ServiceCreator.create(source)
|
||||
val service: Call<ArrayList<Post_yand>> = postService.getPostData("100",tage, page)
|
||||
request(service,safeMode, handler)
|
||||
}
|
||||
|
||||
fun <T:Post> callBack(handler: Handler,status: CallBackStatus,value:ArrayList<T>){
|
||||
val msg = Message.obtain()
|
||||
msg.what = status.ordinal
|
||||
msg.obj = value
|
||||
handler.sendMessage(msg)
|
||||
}
|
||||
|
||||
fun callBack(handler: Handler,status: CallBackStatus){
|
||||
val msg = Message.obtain()
|
||||
msg.what = status.ordinal
|
||||
handler.sendMessage(msg)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param service ArrayList接收边界为Post的泛型,若直接使用Post作为泛型参数,需要强制类型转换。
|
||||
*/
|
||||
fun <T : Post> request(service:Call<ArrayList<T>>,safeMode: Boolean,handler: Handler){
|
||||
|
||||
service.enqueue(object : Callback<ArrayList<T>>{
|
||||
override fun onResponse(call: Call<ArrayList<T>>, response: Response<ArrayList<T>>) {
|
||||
val getValue:ArrayList<T>? = response.body()
|
||||
|
||||
if (getValue!=null) {
|
||||
if (getValue.size==0){
|
||||
callBack(handler,CallBackStatus.DATAISNULL)
|
||||
return
|
||||
}
|
||||
if (safeMode) {
|
||||
val iter = getValue.iterator()
|
||||
while (iter.hasNext()) {
|
||||
val post = iter.next()
|
||||
if (post.rating != "s")
|
||||
iter.remove()
|
||||
}
|
||||
}
|
||||
callBack(handler,CallBackStatus.OK,getValue)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<ArrayList<T>>, t: Throwable) {
|
||||
callBack(handler,CallBackStatus.NETWORKERROR)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,33 +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.bean.Author
|
||||
|
||||
class AuthorAdapter(val tagList: List<Author>) : RecyclerView.Adapter<AuthorAdapter.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]
|
||||
holder.tagText.text = tag.author
|
||||
if (position == 0) {
|
||||
holder.tagText.setBackgroundResource(R.drawable.title_bg)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return tagList.size
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,8 @@ 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.bean.ID
|
||||
import com.lsp.view.bean.Tags
|
||||
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) {
|
||||
@@ -54,9 +54,6 @@ class IdAdapter(val idList: List<ID>,val context: Context) : RecyclerView.Adapte
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val tag = idList[position]
|
||||
holder.tagText.text = tag.id
|
||||
if (position == 0) {
|
||||
holder.tagText.setBackgroundResource(R.drawable.title_bg)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
|
||||
@@ -6,13 +6,13 @@ 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 android.widget.ProgressBar
|
||||
import androidx.activity.addCallback
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.graphics.createBitmap
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.DataSource
|
||||
import com.bumptech.glide.load.engine.GlideException
|
||||
@@ -27,20 +27,16 @@ import com.google.android.material.snackbar.Snackbar
|
||||
import com.lsp.view.R
|
||||
import com.lsp.view.activity.BaseActivity
|
||||
import com.lsp.view.activity.main.MainActivity
|
||||
import com.lsp.view.bean.Author
|
||||
import com.lsp.view.bean.ID
|
||||
import com.lsp.view.bean.Size
|
||||
import com.lsp.view.bean.Tags
|
||||
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 java.io.File
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
|
||||
class PicActivity : BaseActivity() {
|
||||
|
||||
|
||||
private val tagList = ArrayList<Tags>()
|
||||
private val authorList = ArrayList<Author>()
|
||||
private val idList = ArrayList<ID>()
|
||||
private val sizeList = ArrayList<Size>()
|
||||
private lateinit var image: ImageView
|
||||
@@ -51,16 +47,17 @@ class PicActivity : BaseActivity() {
|
||||
|
||||
companion object{
|
||||
fun actionStartActivity(context: Context,id:String,sample_url:String,file_url:String,tags:String,
|
||||
file_ext:String,author:String,file_size:String,md5: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("author", author)
|
||||
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)
|
||||
|
||||
}
|
||||
@@ -76,6 +73,14 @@ class PicActivity : BaseActivity() {
|
||||
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")
|
||||
@@ -83,29 +88,12 @@ class PicActivity : BaseActivity() {
|
||||
loadTags(tags, "tags")
|
||||
}
|
||||
|
||||
|
||||
val author = intent.getStringExtra("author")
|
||||
if (author != null) {
|
||||
loadTags(author, "author")
|
||||
}
|
||||
val file_size = intent.getStringExtra("file_size")
|
||||
if (file_size != null) {
|
||||
loadTags(file_size, "size")
|
||||
}
|
||||
md5 = intent.getStringExtra("md5")
|
||||
|
||||
val sharedPreferences = getSharedPreferences("FirstRun", 0)
|
||||
val firstRun = sharedPreferences.getBoolean("FirstRun", true)
|
||||
if (firstRun) {
|
||||
val sharedPreferences = getSharedPreferences("FirstRun", 0).edit()
|
||||
sharedPreferences.putBoolean("FirstRun", false).apply()
|
||||
val FileD =
|
||||
File("${Environment.getExternalStorageDirectory()}/${Environment.DIRECTORY_PICTURES}/LspMake")
|
||||
FileD.mkdirs()
|
||||
|
||||
}
|
||||
|
||||
|
||||
val id = intent.getStringExtra("id")
|
||||
if (id != null) {
|
||||
loadTags(id, "id")
|
||||
@@ -177,19 +165,22 @@ class PicActivity : BaseActivity() {
|
||||
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (photoView.visibility == View.GONE) {
|
||||
super.onBackPressed()
|
||||
} else {
|
||||
photoView.animate()
|
||||
.alpha(0f)
|
||||
.setDuration(shortAnnotationDuration.toLong())
|
||||
.setListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
photoView.visibility = View.GONE
|
||||
}
|
||||
})
|
||||
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) {
|
||||
@@ -208,9 +199,7 @@ class PicActivity : BaseActivity() {
|
||||
target: Target<Drawable?>?,
|
||||
isFirstResource: Boolean
|
||||
): Boolean {
|
||||
if (e != null) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
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 {
|
||||
@@ -259,6 +248,7 @@ class PicActivity : BaseActivity() {
|
||||
//设置tags列表
|
||||
//这写的很烂 得改
|
||||
private fun loadTags(tags: String, type: String) {
|
||||
val tagList = ArrayList<Tags>()
|
||||
|
||||
when (type) {
|
||||
"tags" -> {
|
||||
@@ -282,15 +272,6 @@ class PicActivity : BaseActivity() {
|
||||
})
|
||||
tagRecyclerView.adapter = adapter
|
||||
}
|
||||
"author" -> {
|
||||
authorList.add(Author("Author"))
|
||||
val authorRecyclerView =
|
||||
findViewById<androidx.recyclerview.widget.RecyclerView>(R.id.authorRecyclerView)
|
||||
authorRecyclerView.layoutManager = layoutManager()
|
||||
authorList.add(Author(tags))
|
||||
val adapter = AuthorAdapter(authorList)
|
||||
authorRecyclerView.adapter = adapter
|
||||
}
|
||||
"id" -> {
|
||||
idList.add(ID("ID"))
|
||||
idList.add(ID(tags))
|
||||
|
||||
@@ -6,7 +6,7 @@ import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.lsp.view.R
|
||||
import com.lsp.view.bean.Size
|
||||
import com.lsp.view.repository.bean.Size
|
||||
import java.math.RoundingMode
|
||||
import java.text.DecimalFormat
|
||||
|
||||
@@ -25,7 +25,6 @@ class SizeAdapter(val tagList: List<Size>) : RecyclerView.Adapter<SizeAdapter.Vi
|
||||
val tag = tagList[position]
|
||||
if (position == 0) {
|
||||
holder.tagText.text = tag.file_size
|
||||
holder.tagText.setBackgroundResource(R.drawable.title_bg)
|
||||
} else {
|
||||
val sizeKb = tag.file_size.toFloat() / 1024
|
||||
val format = DecimalFormat("0.##")
|
||||
|
||||
@@ -10,7 +10,7 @@ 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.bean.Tags
|
||||
import com.lsp.view.repository.bean.Tags
|
||||
|
||||
class TagAdapter(val tagList: List<Tags>, val context: Context) :
|
||||
RecyclerView.Adapter<TagAdapter.ViewHolder>() {
|
||||
@@ -68,9 +68,6 @@ class TagAdapter(val tagList: List<Tags>, val context: Context) :
|
||||
holder.tagText.setOnClickListener {
|
||||
mOnItemClickListener.onItemClick(it, position)
|
||||
}
|
||||
if (position == 0) {
|
||||
holder.tagText.setBackgroundResource(R.drawable.title_bg)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
package com.lsp.view.bean
|
||||
|
||||
class Author(val author: String)
|
||||
@@ -1,3 +0,0 @@
|
||||
package com.lsp.view.bean
|
||||
|
||||
class ID(val id: String)
|
||||
@@ -1,3 +0,0 @@
|
||||
package com.lsp.view.bean
|
||||
|
||||
class Size(val file_size: String)
|
||||
@@ -1,3 +0,0 @@
|
||||
package com.lsp.view.bean
|
||||
|
||||
class Tags(val tag: String)
|
||||
@@ -0,0 +1,132 @@
|
||||
package com.lsp.view.model
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.os.Message
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.AbstractSavedStateViewModelFactory
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.lsp.view.activity.main.PostAdapter
|
||||
import com.lsp.view.repository.PostRepository
|
||||
import androidx.savedstate.SavedStateRegistryOwner
|
||||
import com.lsp.view.repository.bean.YandPost
|
||||
import com.lsp.view.repository.exception.NetworkErrorException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class MainViewModel(private val repository: PostRepository,private val context: Context):ViewModel() {
|
||||
private val _uiState = MutableStateFlow(UiState())
|
||||
val uiState:StateFlow<UiState> = _uiState.asStateFlow()
|
||||
private var fetchJob: Job? = null
|
||||
val adapter = PostAdapter(context)
|
||||
private val TAG = this::class.java.simpleName
|
||||
|
||||
companion object {
|
||||
fun provideFactory(
|
||||
repository: PostRepository,
|
||||
context: Context,
|
||||
owner: SavedStateRegistryOwner,
|
||||
defaultArgs: Bundle? = null,
|
||||
|
||||
): AbstractSavedStateViewModelFactory =
|
||||
object : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(
|
||||
key: String,
|
||||
modelClass: Class<T>,
|
||||
handle: SavedStateHandle
|
||||
): T {
|
||||
return MainViewModel(repository, context) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
init {
|
||||
//初始化写入
|
||||
val configSp = context.getSharedPreferences("com.lsp.view_preferences", 0)
|
||||
if (configSp.getString("source_name", null) == null) {
|
||||
configSp.edit().putString("source_name", "yande.re").apply()
|
||||
configSp.edit().putString("type", "0").apply()
|
||||
}
|
||||
|
||||
_uiState.update {
|
||||
it.copy(nowSourceName = configSp.getString("source_name",null))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun fetchNewPost(){
|
||||
fetchJob?.cancel()
|
||||
fetchJob = viewModelScope.launch(Dispatchers.IO) {
|
||||
|
||||
_uiState.value.isRefreshing.postValue(true)
|
||||
|
||||
try {
|
||||
val postList = repository.fetchPostData(
|
||||
_uiState.value.nowSearchText,
|
||||
_uiState.value.isSafe,
|
||||
_uiState.value.nowPage
|
||||
)
|
||||
|
||||
launch(Dispatchers.Main) {
|
||||
if (_uiState.value.isAppend){
|
||||
adapter.appendDate(postList)
|
||||
}else{
|
||||
adapter.pushNewData(postList)
|
||||
}
|
||||
}
|
||||
|
||||
}catch (e:NetworkErrorException){
|
||||
launch(Dispatchers.Main){
|
||||
Toast.makeText(context,e.message,Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
_uiState.value.isRefreshing.postValue(false)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
fun fetchNewPostBySearch(target:String){
|
||||
_uiState.update {
|
||||
it.copy(nowSearchText = target)
|
||||
}
|
||||
|
||||
fetchNewPost()
|
||||
}
|
||||
|
||||
fun fetchPostByRefresh(){
|
||||
_uiState.update {
|
||||
it.copy(nowPage = 1)
|
||||
}
|
||||
|
||||
fetchNewPost()
|
||||
}
|
||||
|
||||
fun appendPost(){
|
||||
|
||||
_uiState.update {
|
||||
it.copy(isAppend = true)
|
||||
}
|
||||
|
||||
fetchNewPost()
|
||||
|
||||
_uiState.update {
|
||||
it.copy(isAppend = false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.lsp.view.model
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
|
||||
data class UiState(
|
||||
var showSearchBar:Boolean = false,
|
||||
val isRefreshing:MutableLiveData<Boolean> = MutableLiveData(),
|
||||
val nowSearchText:String = "",
|
||||
val nowSourceName: String? = null,
|
||||
val isSafe: Boolean = true, //安全模式
|
||||
val nowPage:Int = 1,
|
||||
val isAppend:Boolean = false
|
||||
){
|
||||
fun switchShowSearchBar(){
|
||||
showSearchBar = !showSearchBar
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.lsp.view.repository
|
||||
|
||||
import com.lsp.view.R
|
||||
import com.lsp.view.YandViewApplication
|
||||
import com.lsp.view.repository.exception.UnableConstructObjectException
|
||||
import com.lsp.view.repository.api.PostApi
|
||||
import com.lsp.view.repository.api.PostApiImpl
|
||||
import com.lsp.view.repository.bean.YandPost
|
||||
|
||||
class PostDataSource {
|
||||
private val api: PostApi = PostApiImpl()
|
||||
|
||||
|
||||
|
||||
//设置列表数据
|
||||
suspend fun fetchNewPost(load: Load): ArrayList<YandPost> {
|
||||
return api.fetchNewPost(load)
|
||||
}
|
||||
}
|
||||
data class Load(
|
||||
val tags: String?,
|
||||
val page: Int,
|
||||
val safe:Boolean
|
||||
){
|
||||
lateinit var source:String
|
||||
|
||||
companion object{
|
||||
fun Builder(tags: String?, page: Int, safe:Boolean):Load{
|
||||
val sourceNameArray = YandViewApplication.context!!.resources.getStringArray(R.array.pic_source)
|
||||
val sourceUrlArray = YandViewApplication.context!!.resources.getStringArray(R.array.url_source)
|
||||
val configSp = YandViewApplication.context?.getSharedPreferences("com.lsp.view_preferences", 0)
|
||||
val nowSourceName: String? = configSp?.getString("source_name",null)
|
||||
val load = Load(tags,page,safe)
|
||||
|
||||
//初始化数据
|
||||
for ((index,sourceName) in sourceNameArray.withIndex()){
|
||||
if (sourceName == nowSourceName){
|
||||
load.source = sourceUrlArray[index]
|
||||
return load
|
||||
}
|
||||
}
|
||||
|
||||
throw UnableConstructObjectException("Unable construct load object.")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.lsp.view.repository
|
||||
|
||||
import android.os.Handler
|
||||
import com.lsp.view.repository.bean.YandPost
|
||||
|
||||
|
||||
class PostRepository {
|
||||
private val dataSource = PostDataSource()
|
||||
|
||||
//获取post
|
||||
suspend fun fetchPostData(searchTarget :String?,safe:Boolean,page:Int): ArrayList<YandPost> {
|
||||
|
||||
var target = searchTarget
|
||||
var isNum = true
|
||||
|
||||
//如果检索目标是纯数字,则按照id搜索
|
||||
try {
|
||||
target?.toLong()
|
||||
}catch (e:NumberFormatException){
|
||||
isNum = false
|
||||
}
|
||||
|
||||
if (isNum){
|
||||
target = "id:$searchTarget"
|
||||
}
|
||||
|
||||
val load = Load.Builder(target,page,safe)
|
||||
|
||||
return dataSource.fetchNewPost(load)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.lsp.view.repository.api
|
||||
|
||||
import android.util.Log
|
||||
import com.lsp.view.repository.Load
|
||||
import com.lsp.view.repository.bean.Post
|
||||
import com.lsp.view.repository.bean.YandPost
|
||||
import com.lsp.view.repository.exception.NetworkErrorException
|
||||
import retrofit2.Call
|
||||
import java.net.SocketException
|
||||
|
||||
interface PostApi {
|
||||
private val TAG: String
|
||||
get() = this::class.java.simpleName
|
||||
|
||||
/**
|
||||
* @param service ArrayList接收边界为Post的泛型,若直接使用Post作为泛型参数,需要强制类型转换。
|
||||
*/
|
||||
@Throws(NetworkErrorException::class)
|
||||
fun <T : Post> request(service: Call<ArrayList<T>>, safeMode: Boolean):ArrayList<T> {
|
||||
|
||||
try {
|
||||
val execute = service.execute()
|
||||
return if (execute.isSuccessful) {
|
||||
if (execute.body() != null) {
|
||||
Log.e(TAG, execute.body().toString())
|
||||
execute.body()!!
|
||||
|
||||
} else {
|
||||
//结果为空,返回空集避免空指针
|
||||
ArrayList()
|
||||
}
|
||||
} else {
|
||||
throw NetworkErrorException(execute.errorBody().toString())
|
||||
}
|
||||
|
||||
}catch (e: Exception){
|
||||
throw NetworkErrorException(e.message)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun fetchNewPost(load:Load):ArrayList<YandPost>
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.lsp.view.repository.api
|
||||
|
||||
import com.lsp.view.repository.Load
|
||||
import com.lsp.view.retrofit.PostService
|
||||
import com.lsp.view.retrofit.ServiceCreator
|
||||
import com.lsp.view.repository.bean.YandPost
|
||||
import retrofit2.Call
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class PostApiImpl :PostApi {
|
||||
private val TAG = this::class.java.simpleName
|
||||
private val defaultLimit = "100"
|
||||
override suspend fun fetchNewPost(load: Load):ArrayList<YandPost>{
|
||||
val postService: PostService = ServiceCreator.create(load.source)
|
||||
val service: Call<ArrayList<YandPost>> = postService.getPostData(defaultLimit,load.tags, load.page)
|
||||
|
||||
return request(service, load.safe)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.lsp.view.repository.bean
|
||||
|
||||
class Author(val author: String)
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.lsp.view.repository.bean
|
||||
|
||||
class ID(val id: String)
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.lsp.view.bean
|
||||
package com.lsp.view.repository.bean
|
||||
|
||||
open class Post(
|
||||
val id: String,
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.lsp.view.repository.bean
|
||||
|
||||
class Size(val file_size: String)
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.lsp.view.repository.bean
|
||||
|
||||
class Tags(val tag: String)
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
package com.lsp.view.bean
|
||||
package com.lsp.view.repository.bean
|
||||
|
||||
class Post_yand(
|
||||
class YandPost(
|
||||
val preview_url: String,
|
||||
val file_url: String,
|
||||
val sample_url: String,
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.lsp.view.repository.exception
|
||||
|
||||
import okhttp3.ResponseBody
|
||||
|
||||
class NetworkErrorException(override val message: String?) : Exception() {
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.lsp.view.repository.exception
|
||||
|
||||
import java.lang.Exception
|
||||
|
||||
class UnableConstructObjectException(override val message: String?):Exception(message) {
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.lsp.view.retrofit
|
||||
|
||||
import com.lsp.view.bean.Post_yand
|
||||
import com.lsp.view.repository.bean.YandPost
|
||||
import retrofit2.Call
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Query
|
||||
@@ -11,5 +11,5 @@ interface PostService {
|
||||
@Query("limit") limit: String,
|
||||
@Query("tags") tags: String?,
|
||||
@Query("page") page: Int
|
||||
): Call<ArrayList<Post_yand>>
|
||||
): Call<ArrayList<YandPost>>
|
||||
}
|
||||
@@ -11,13 +11,11 @@ object ServiceCreator {
|
||||
* @param source:加载根地址
|
||||
*
|
||||
*/
|
||||
var source: String? = null
|
||||
fun <T> create(serviceClass: Class<T>, source: String): T {
|
||||
val retrofit = Retrofit.Builder()
|
||||
.baseUrl(source)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
ServiceCreator.source = source
|
||||
return retrofit.create(serviceClass)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.media.MediaScannerConnection
|
||||
import android.os.*
|
||||
import com.lsp.view.util.CallBackStatus
|
||||
import com.lsp.view.util.Util
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import java.io.File
|
||||
@@ -19,12 +19,9 @@ class DownloadService : Service() {
|
||||
|
||||
class DownloadBinder(val context: Context) : Binder() {
|
||||
|
||||
fun callBack(handler: Handler,status:CallBackStatus,obj:Any?=null){
|
||||
fun callBack(handler: Handler,status:Int){
|
||||
val msg = Message.obtain()
|
||||
msg.what = status.ordinal
|
||||
if (obj!=null){
|
||||
msg.obj = obj
|
||||
}
|
||||
msg.obj = status
|
||||
handler.sendMessage(msg)
|
||||
|
||||
}
|
||||
@@ -38,7 +35,7 @@ class DownloadService : Service() {
|
||||
File("${Environment.getExternalStorageDirectory()}/${Environment.DIRECTORY_PICTURES}/LspMake/$md5.$end")
|
||||
|
||||
if (file.exists()){
|
||||
callBack(handler,CallBackStatus.FILEEXISTS)
|
||||
callBack(handler,Util.FILE_EXISTS)
|
||||
return@thread
|
||||
}
|
||||
|
||||
@@ -60,24 +57,24 @@ class DownloadService : Service() {
|
||||
null, null
|
||||
)
|
||||
if (md5 == getFileMD5(file.path)) {
|
||||
callBack(handler, CallBackStatus.OK,file)
|
||||
callBack(handler, Util.DOWNLOAD_SUCCESS)
|
||||
} else {
|
||||
file.delete()
|
||||
callBack(handler,CallBackStatus.MD5COMPAREERROR)
|
||||
callBack(handler,Util.MD5_COMPARE_ERROR)
|
||||
}
|
||||
|
||||
return@thread
|
||||
|
||||
} else {
|
||||
file.delete()
|
||||
callBack(handler, CallBackStatus.NETWORKERROR)
|
||||
callBack(handler, Util.NETWORK_ERROR)
|
||||
return@thread
|
||||
}
|
||||
|
||||
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
callBack(handler, CallBackStatus.DOWNLOADERROR)
|
||||
callBack(handler, Util.DOWNLOAD_ERROR)
|
||||
return@thread
|
||||
} finally {
|
||||
fos.close()
|
||||
@@ -87,7 +84,7 @@ class DownloadService : Service() {
|
||||
FileD.mkdirs()
|
||||
downloadPic(file_url, end, handler, md5)
|
||||
}
|
||||
callBack(handler,CallBackStatus.DOWNLOADERROR)
|
||||
callBack(handler,Util.DOWNLOAD_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.lsp.view.util
|
||||
|
||||
enum class CallBackStatus {
|
||||
OK, NETWORKERROR, DATAISNULL, DOWNLOADERROR, SETWP, MD5COMPAREERROR, FILEEXISTS
|
||||
}
|
||||
@@ -5,6 +5,7 @@ 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
|
||||
@@ -17,6 +18,12 @@ 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()
|
||||
@@ -36,20 +43,23 @@ object Util {
|
||||
|
||||
val imageUri = FileProvider.getUriForFile(
|
||||
context,
|
||||
"com.lsper.view.fileprovider",
|
||||
"com.lsp.view.fileprovider",
|
||||
file
|
||||
)
|
||||
|
||||
context.grantUriPermission("com.lsper.view",imageUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
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> = context.packageManager
|
||||
.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
|
||||
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
|
||||
@@ -78,20 +88,20 @@ object Util {
|
||||
private val handler = object : Handler(Looper.myLooper()!!){
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when(msg.what){
|
||||
CallBackStatus.OK.ordinal ->{
|
||||
when(msg.obj){
|
||||
DOWNLOAD_SUCCESS ->{
|
||||
Toast.makeText(YandViewApplication.context, R.string.toast_download_success, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
CallBackStatus.DOWNLOADERROR.ordinal -> {
|
||||
DOWNLOAD_ERROR -> {
|
||||
Toast.makeText(YandViewApplication.context, R.string.toast_download_fail, Toast.LENGTH_SHORT).show()
|
||||
|
||||
}
|
||||
CallBackStatus.MD5COMPAREERROR.ordinal -> {
|
||||
MD5_COMPARE_ERROR -> {
|
||||
Toast.makeText(YandViewApplication.context, R.string.toast_compar_md5_fail, Toast.LENGTH_SHORT).show()
|
||||
|
||||
}
|
||||
CallBackStatus.FILEEXISTS.ordinal -> {
|
||||
FILE_EXISTS -> {
|
||||
Toast.makeText(YandViewApplication.context, R.string.toast_file_exist, Toast.LENGTH_SHORT).show()
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<vector android:height="24dp" android:tint="#000000"
|
||||
<vector 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="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:tint="#000000" android:viewportHeight="24"
|
||||
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,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="M11,7L9.6,8.4l2.6,2.6H2v2h10.2l-2.6,2.6L11,17l5,-5L11,7zM20,19h-8v2h8c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2h-8v2h8V19z"/>
|
||||
</vector>
|
||||
@@ -1,5 +0,0 @@
|
||||
<vector android:height="40dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="20" android:viewportWidth="20"
|
||||
android:width="40dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
|
||||
</vector>
|
||||
@@ -1,41 +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:orientation="vertical"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".activity.login.LoginActivity">
|
||||
<TextView
|
||||
android:layout_marginTop="160dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="44sp"
|
||||
android:id="@+id/title"
|
||||
android:text="@string/activity_login_login"/>
|
||||
<EditText
|
||||
android:hint="@string/activity_login_account"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/username"/>
|
||||
<EditText
|
||||
android:hint="@string/activity_login_password"
|
||||
android:inputType="textPassword"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/password"/>
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:id="@+id/login"
|
||||
android:background="@color/primary"
|
||||
android:src="@drawable/ic_baseline_navigate_next_24"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_gravity="center"
|
||||
android:elevation="8dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -19,83 +19,49 @@
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
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
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:menu="@menu/toolbar_menu"
|
||||
android:id="@+id/toolbar"
|
||||
>
|
||||
<EditText
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:menu="@menu/toolbar_menu"
|
||||
android:id="@+id/toolbar"
|
||||
app:layout_scrollFlags="scroll|enterAlways|snap"
|
||||
/>
|
||||
android:layout_height="match_parent"
|
||||
android:textSize="20sp"
|
||||
android:id="@+id/search"
|
||||
android:imeOptions="actionSearch"
|
||||
android:singleLine="true"
|
||||
android:visibility="gone" />
|
||||
</androidx.appcompat.widget.Toolbar>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
android:id="@+id/swipeRefreshLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
android:id="@+id/swipeRefreshLayout"
|
||||
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>
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/recyclerview"/>
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_marginTop="?attr/actionBarSize"
|
||||
android:paddingTop="40dp"
|
||||
android:visibility="gone"
|
||||
android:id="@+id/search_bar"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"/>
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="20"
|
||||
android:elevation="15dp"
|
||||
app:cardCornerRadius="3dp"
|
||||
android:id="@+id/editCard"
|
||||
style="?attr/materialCardViewElevatedStyle"
|
||||
android:layout_height="50dp"
|
||||
>
|
||||
<EditText
|
||||
|
||||
android:background="@null"
|
||||
android:hint="搜索..."
|
||||
android:imeOptions="actionSearch"
|
||||
android:singleLine="true"
|
||||
android:paddingStart="10dp"
|
||||
android:textSize="15sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:id="@+id/search"/>
|
||||
<View
|
||||
android:id="@+id/close"
|
||||
android:layout_gravity="end"
|
||||
android:layout_width="35dp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="35dp"
|
||||
app:tint="?attr/colorPrimary"
|
||||
android:background="@drawable/ic_baseline_close_24"/>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"/>
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
<com.google.android.material.navigation.NavigationView
|
||||
android:layout_width="240dp"
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
android:layout_height="match_parent"
|
||||
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="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed">
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
@@ -34,7 +34,7 @@
|
||||
android:fitsSystemWindows="true"
|
||||
android:id="@+id/titleImage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="centerCrop"
|
||||
android:contentDescription="@string/appbar_scrolling_view_behavior"/>
|
||||
|
||||
@@ -52,13 +52,13 @@
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
style="?attr/materialCardViewElevatedStyle"
|
||||
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="15dp"
|
||||
android:layout_marginTop="5dp"
|
||||
app:cardCornerRadius="10dp">
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/fav_tag"
|
||||
android:layout_margin="5dp"
|
||||
android:padding="5dp"
|
||||
android:textSize="20sp"
|
||||
android:textColor="#fff"
|
||||
android:background="@drawable/item_bg"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
|
||||
<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>
|
||||
@@ -1,14 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
android:padding="5dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<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:textColor="#fff"
|
||||
android:background="@drawable/item_bg"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/tag"/>
|
||||
</LinearLayout>
|
||||
android:layout_height="wrap_content"/>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
app:defaultValue="yande.re"
|
||||
app:entries="@array/pic_source"
|
||||
app:entryValues="@array/pic_source"
|
||||
app:key="sourceName"
|
||||
app:key="source_name"
|
||||
app:title="@string/setting_item_select_source"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.2.2'
|
||||
classpath 'com.android.tools.build:gradle:7.3.0'
|
||||
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
||||
Reference in New Issue
Block a user