Update Compose

This commit is contained in:
AnranYus
2024-06-29 21:58:26 +08:00
parent 5d84fc4df2
commit e9c1f9d176
57 changed files with 91 additions and 1250 deletions
+7 -21
View File
@@ -10,11 +10,11 @@ android {
compileSdkVersion = 34
defaultConfig {
applicationId "com.lsp.view"
applicationId "moe.uni.moe"
minSdkVersion 29
targetSdkVersion 34
versionCode 221022
versionName "1.2.7"
versionCode 240629
versionName "2.0.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
@@ -27,12 +27,10 @@ android {
debuggable true
minifyEnabled false
shrinkResources false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
@@ -42,7 +40,7 @@ android {
kotlinOptions {
jvmTarget = '1.8'
}
namespace 'com.lsp.view'
namespace 'moe.uni.view'
buildFeatures {
compose true
}
@@ -58,7 +56,6 @@ android {
dependencies {
implementation("androidx.navigation:navigation-compose:2.7.7")
implementation("com.squareup.okhttp3:logging-interceptor:4.9.1")
implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.2'
@@ -73,29 +70,18 @@ dependencies {
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
debugImplementation 'androidx.compose.ui:ui-tooling'
debugImplementation 'androidx.compose.ui:ui-test-manifest'
def room_version = "2.5.0"
implementation("io.coil-kt:coil-compose:2.6.0")
def room_version = "2.6.1"
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-viewmodel-compose:2.6.1")
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 'jp.wasabeef:recyclerview-animators:4.0.2'
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
implementation 'com.google.android.flexbox:flexbox:3.0.0'
implementation ('androidx.swiperefreshlayout:swiperefreshlayout:1.1.0')
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.2")
implementation ('com.squareup.retrofit2:retrofit:2.9.0')
implementation ('com.squareup.retrofit2:converter-gson:2.9.0')
implementation 'com.github.bumptech.glide:glide:4.12.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'
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.22"
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.0"
implementation 'androidx.core:core-ktx:1.13.1'
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+1 -5
View File
@@ -25,7 +25,7 @@
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.lsp.view.fileprovider"
android:authorities="moe.uni.view.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
@@ -38,11 +38,7 @@
android:name=".service.DownloadService"
android:enabled="true"
android:exported="true" />
<activity
android:name=".ui.activity.MainActivity"
android:exported="true">
</activity>
</application>
</manifest>
@@ -1,190 +0,0 @@
package com.lsp.view.ui
import android.content.Context
import android.os.Bundle
import androidx.lifecycle.AbstractSavedStateViewModelFactory
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.lsp.view.ui.fragment.adapter.PostAdapter
import com.lsp.view.repository.network.PostRepository
import androidx.savedstate.SavedStateRegistryOwner
import com.lsp.view.YandViewApplication
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 kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
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, context: Context):ViewModel() {
private val _uiState = MutableStateFlow(UiState())
val uiState:StateFlow<UiState>
get() = _uiState.asStateFlow()
private var fetchJob: Job? = null
private val TAG = this::class.java.simpleName
private val _toastMessage = MutableLiveData<String>()
val toastMessage
get() = _toastMessage as LiveData<String>
private val _postList = MutableLiveData<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
private val _tagsList = MutableLiveData<ArrayList<String>>()
val tagsList get() = _tagsList as LiveData<ArrayList<String>>
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.apply {
it.nowSourceName.postValue(configSp.getString("source_name",null))
}
it.copy(isSafe = configSp.getBoolean("safe_mode",true))
}
}
private fun fetchNewPost() {
fetchJob?.cancel()
fetchJob = viewModelScope.launch(Dispatchers.IO) {
_uiState.value.isRefreshing.postValue(true)
try {
val newPosts = repository.fetchPostData(
_uiState.value.nowSearchText.value,
_uiState.value.nowPage
)
val currentPosts = _postList.value ?: arrayListOf()
currentPosts.addAll(0,newPosts)
_postList.postValue(currentPosts)
} catch (e: NetworkErrorException) {
postNewToast(e.message.toString())
}
_uiState.value.isRefreshing.postValue(false)
}
}
fun fetchPostByRefresh(){
_uiState.update {
it.copy(nowPage = 1)
}
fetchNewPost()
}
fun fetchPostBySearch(searchTarget:String){
_uiState.update {
it.apply {
it.nowSearchText.postValue(searchTarget)
}
}
fetchNewPost()
}
fun fetchMore(){
_uiState.value.nowPage++
fetchNewPost()
}
fun updateSafeMode(mode:Boolean){
_uiState.update {
it.copy(isSafe = mode)
}
fetchNewPost()
}
fun updateNowSource(source:String){
_uiState.value.nowSourceName.postValue(source)
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,12 +0,0 @@
package com.lsp.view.ui
import androidx.lifecycle.MutableLiveData
data class UiState(
var showSearchBar:Boolean = false,
val isRefreshing:MutableLiveData<Boolean> = MutableLiveData(),
var nowSearchText:MutableLiveData<String> = MutableLiveData(""),
val nowSourceName: MutableLiveData<String> = MutableLiveData(),
val isSafe: Boolean = true, //安全模式
var nowPage:Int = 1,
)
@@ -1,60 +0,0 @@
package com.lsp.view.ui.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.ui.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()
}
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,81 +0,0 @@
package com.lsp.view.ui.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.ui.fragment.adapter.PostAdapter
import com.lsp.view.R
import com.lsp.view.ui.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) {
ImageFragment.navigationToImageFragment(activityContext,post,view,R.id.action_collectFragment_to_imageFragment)
}
})
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
}
}
}
@@ -1,218 +0,0 @@
package com.lsp.view.ui.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.view.animation.AnimationUtils
import android.widget.ImageView
import androidx.core.content.FileProvider
import androidx.lifecycle.lifecycleScope
import androidx.navigation.Navigation
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.ui.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){
}
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)
}
}
companion object{
fun navigationToImageFragment(context:MainActivity ,post:Post,view:View,fragmentId:Int){
val bundle = Bundle()
bundle.putParcelable("post",post)
val tags = post.tags?.split(",")?.toList()
context.viewModel.tagsList.value?.apply {
clear()
tags?.let { addAll(it) }
}
Navigation.findNavController(view).navigate(fragmentId,bundle)
val slideOutAnimation = AnimationUtils.loadAnimation(context,
R.anim.slide_out_bottom
)
context.bottomNav.startAnimation(slideOutAnimation)
context.bottomNav.visibility = View.GONE
}
}
}
@@ -1,108 +0,0 @@
package com.lsp.view.ui.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.ui.fragment.adapter.PostAdapter
import com.lsp.view.R
import com.lsp.view.ui.activity.MainActivity
import com.lsp.view.bean.Post
import com.lsp.view.ui.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) {
ImageFragment.navigationToImageFragment(activityContext,post,view,R.id.action_postListFragment_to_imageFragment)
}
})
}
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
}
}
}
@@ -1,12 +0,0 @@
package com.lsp.view.ui.fragment
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat
import com.lsp.view.R
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
}
}
@@ -1,143 +0,0 @@
package com.lsp.view.ui.fragment.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
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.YandViewApplication
import com.lsp.view.bean.Post
class PostAdapter(val context: Context,private val postList: ArrayList<Post> = ArrayList()):
RecyclerView.Adapter<PostAdapter.ViewHolder>() {
val TAG = this::class.java.simpleName
private var inBottom:Boolean = false//当前列表是否在底部
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val picImage: ImageView = view.findViewById(R.id.image)
}
fun pushNewData(list: List<Post>) {
if (inBottom) {
//在底部,则追加数据
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)
}
inBottom = false//加入新数据后不在底部,若仍在底部说明无更多数据,也不必处理
}
private lateinit var mOnListItemClick: OnListItemClick
interface OnListItemClick {
fun setOnListItemClick(post:Post)
}
fun setOnListItemClick(mOnListItemClick: OnListItemClick) {
this.mOnListItemClick = mOnListItemClick
}
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
mOnListItemClick.setOnListItemClick(postList[position])
}
return viewHolder
}
private lateinit var mScrollToBottom: OnScrollToBottom
interface OnScrollToBottom {
fun event(position: Int)
}
fun setLoadMoreListener(mLoadMoreListener: OnScrollToBottom) {
this.mScrollToBottom = mLoadMoreListener
}
private fun preLoad(p:Int){
if (p%20==0){
//执行预加载
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 = postList[index].sampleUrl
val glideUrl = GlideUrl(
source,
LazyHeaders.Builder().addHeader("User-Agent", YandViewApplication.UA)
.build()
)
Glide.with(context).download(glideUrl).preload()
}
}
}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
preLoad(position)
val post = postList[position]
val source: String = post.sampleUrl
val height = postList[position].sampleHeight
val width = postList[position].sampleWidth
//图片过长则缩减高度以保证显示完整
if (width > height){
holder.picImage.layoutParams.height = height / 2
}else {
holder.picImage.layoutParams.height = height
}
val glideUrl = GlideUrl(
source,
LazyHeaders.Builder().addHeader("User-Agent", YandViewApplication.UA)
.build()
)
Glide.with(context).load(glideUrl).into(holder.picImage)
if (position == postList.size - 1 && postList.size > 6 ) {
//到达底部
inBottom = true
if (this::mScrollToBottom.isInitialized) {
mScrollToBottom.event(position)
}
}
}
override fun getItemCount(): Int {
return postList.size
}
}
@@ -1,28 +0,0 @@
package com.lsp.view.ui.fragment.adapter
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
class TagsAdapter(private val tagList:List<String>):RecyclerView.Adapter<TagsAdapter.ViewHolder>() {
inner class ViewHolder(view:View):RecyclerView.ViewHolder(view) {
val tagItem = view.findViewById<TextView>(R.id.tag)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.tags_item_layout, parent, false)
val viewHolder = ViewHolder(view)
return viewHolder
}
override fun getItemCount() = tagList.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.tagItem.text = tagList[position]
}
}
@@ -1,9 +1,8 @@
package com.lsp.view
package moe.uni.view
import android.app.Application
import androidx.lifecycle.DefaultLifecycleObserver
import android.content.Context
import com.google.android.material.color.DynamicColors
class YandViewApplication : Application(), DefaultLifecycleObserver {
@@ -11,8 +10,6 @@ class YandViewApplication : Application(), DefaultLifecycleObserver {
override fun onCreate() {
super<Application>.onCreate()
context = applicationContext
DynamicColors.applyToActivitiesIfAvailable(this)
}
companion object {
@@ -1,4 +1,4 @@
package com.lsp.view.bean
package moe.uni.view.bean
import android.os.Parcel
import android.os.Parcelable
@@ -1,4 +1,4 @@
package com.lsp.view.bean
package moe.uni.view.bean
import com.google.gson.annotations.SerializedName
@@ -1,4 +1,4 @@
package com.lsp.view.common
package moe.uni.view.common
class Config(val safeMode:Boolean,val source:String) {
companion object{
@@ -1,4 +1,4 @@
package com.lsp.view.common
package moe.uni.view.common
import android.annotation.SuppressLint
import android.content.Context
@@ -13,7 +13,7 @@ import androidx.core.content.FileProvider
import androidx.core.graphics.drawable.toBitmap
import coil.ImageLoader
import coil.request.ImageRequest
import com.lsp.view.R
import moe.uni.view.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -95,7 +95,7 @@ suspend fun getImageInfo(url: String, context: Context): ImageInfo {
}
val imageUri = FileProvider.getUriForFile(
context,
"com.lsp.view.fileprovider",
"moe.uni.view.fileprovider",
file
)
return ImageInfo(path = file.path, name = fileName, uri = imageUri)
@@ -1,4 +1,4 @@
package com.lsp.view.common
package moe.uni.view.common
object PreKV {
const val SOURCE_NAME = "source_name"
@@ -6,5 +6,5 @@ object PreKV {
}
object Pre{
const val NAME = "com.lsp.view_preferences"
const val NAME = "moe.uni.view_preferences"
}
@@ -1,7 +1,7 @@
package com.lsp.view.common
package moe.uni.view.common
import android.content.Context
import com.lsp.view.YandViewApplication
import moe.uni.view.YandViewApplication
object PreUtils {
private val PRE = YandViewApplication.context!!.getSharedPreferences(Pre.NAME,Context.MODE_PRIVATE)
@@ -1,11 +1,11 @@
package com.lsp.view.repository.datasource
package moe.uni.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
import moe.uni.view.repository.datasource.dao.CollectDao
import moe.uni.view.repository.datasource.model.Collect
@Database(entities = [Collect::class], version = 1,exportSchema = false)
abstract class CollectDatabase: RoomDatabase(){
@@ -1,6 +1,6 @@
package com.lsp.view.repository.datasource
package moe.uni.view.repository.datasource
import com.lsp.view.repository.datasource.model.Collect
import moe.uni.view.repository.datasource.model.Collect
interface CollectRepository {
suspend fun addNewCollect(collect: Collect)
@@ -1,7 +1,7 @@
package com.lsp.view.repository.datasource
package moe.uni.view.repository.datasource
import com.lsp.view.repository.datasource.dao.CollectDao
import com.lsp.view.repository.datasource.model.Collect
import moe.uni.view.repository.datasource.dao.CollectDao
import moe.uni.view.repository.datasource.model.Collect
class CollectRepositoryImpl(private val collectDao:CollectDao):CollectRepository {
override suspend fun addNewCollect(collect: Collect) {
@@ -1,10 +1,10 @@
package com.lsp.view.repository.datasource.dao
package moe.uni.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
import moe.uni.view.repository.datasource.model.Collect
@Dao
interface CollectDao {
@@ -1,11 +1,11 @@
package com.lsp.view.repository.datasource.model
package moe.uni.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
import moe.uni.view.YandViewApplication
import moe.uni.view.bean.Post
@Entity(tableName = "collect")
data class Collect(
@@ -28,7 +28,7 @@ data class Collect(
sampleWeight:Int,
tags:String?
): this(0, postId, sampleUrl, rating, fileUrl, sampleHeight, sampleWeight,
YandViewApplication.context?.getSharedPreferences("com.lsp.view_preferences",Context.MODE_PRIVATE)?.getString("source_name", "yande.re")!!,tags)
YandViewApplication.context?.getSharedPreferences("moe.uni.view_preferences",Context.MODE_PRIVATE)?.getString("source_name", "yande.re")!!,tags)
companion object{
fun Post.toCollect():Collect = Collect(this.postId,this.sampleUrl,this.rating,this.fileUrl,this.sampleHeight,this.sampleWidth ,this.tags)
@@ -1,4 +1,4 @@
package com.lsp.view.repository.exception
package moe.uni.view.repository.exception
import android.util.Log
@@ -1,6 +1,4 @@
package com.lsp.view.repository.exception
import okhttp3.ResponseBody
package moe.uni.view.repository.exception
class NetworkErrorException(override val message: String?) : LoggerException(message) {
}
@@ -1,6 +1,4 @@
package com.lsp.view.repository.exception
import java.lang.Exception
package moe.uni.view.repository.exception
class UnableConstructObjectException(override val message: String?):LoggerException(message) {
}
@@ -1,14 +1,9 @@
package com.lsp.view.repository.network
package moe.uni.view.repository.network
import com.lsp.view.R
import com.lsp.view.YandViewApplication
import com.lsp.view.repository.exception.UnableConstructObjectException
import com.lsp.view.repository.network.api.PostApi
import com.lsp.view.repository.network.api.PostApiImpl
import com.lsp.view.bean.YandPost
import com.lsp.view.common.Config
import com.lsp.view.common.Pre
import com.lsp.view.common.PreKV
import moe.uni.view.repository.network.api.PostApi
import moe.uni.view.repository.network.api.PostApiImpl
import moe.uni.view.bean.YandPost
import moe.uni.view.common.Config
class PostDataSource {
companion object{
@@ -1,7 +1,7 @@
package com.lsp.view.repository.network
package moe.uni.view.repository.network
import com.lsp.view.bean.YandPost
import com.lsp.view.common.Config
import moe.uni.view.bean.YandPost
import moe.uni.view.common.Config
class PostRepository {
@@ -1,9 +1,9 @@
package com.lsp.view.repository.network.api
package moe.uni.view.repository.network.api
import com.lsp.view.repository.network.Load
import com.lsp.view.bean.Post
import com.lsp.view.bean.YandPost
import com.lsp.view.repository.exception.NetworkErrorException
import moe.uni.view.repository.network.Load
import moe.uni.view.bean.Post
import moe.uni.view.bean.YandPost
import moe.uni.view.repository.exception.NetworkErrorException
import retrofit2.Call
interface PostApi {
@@ -1,9 +1,9 @@
package com.lsp.view.repository.network.api
package moe.uni.view.repository.network.api
import com.lsp.view.repository.network.Load
import com.lsp.view.repository.network.retrofit.PostService
import com.lsp.view.repository.network.retrofit.ServiceCreator
import com.lsp.view.bean.YandPost
import moe.uni.view.repository.network.Load
import moe.uni.view.repository.network.retrofit.PostService
import moe.uni.view.repository.network.retrofit.ServiceCreator
import moe.uni.view.bean.YandPost
import retrofit2.Call
import kotlin.collections.ArrayList
@@ -1,6 +1,6 @@
package com.lsp.view.repository.network.retrofit
package moe.uni.view.repository.network.retrofit
import com.lsp.view.bean.YandPost
import moe.uni.view.bean.YandPost
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Query
@@ -1,4 +1,4 @@
package com.lsp.view.repository.network.retrofit
package moe.uni.view.repository.network.retrofit
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
@@ -1,11 +1,11 @@
package com.lsp.view.service
package moe.uni.view.service
import android.app.Service
import android.content.Context
import android.content.Intent
import android.media.MediaScannerConnection
import android.os.*
import com.lsp.view.repository.network.retrofit.ServiceCreator
import moe.uni.view.repository.network.retrofit.ServiceCreator
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
@@ -1,4 +1,4 @@
package com.lsp.view.ui.compose
package moe.uni.view.ui.compose
import android.content.ComponentName
import android.content.Intent
@@ -14,14 +14,14 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.lsp.view.ui.compose.theme.LspViewTheme
import moe.uni.view.ui.compose.theme.LspViewTheme
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.lsp.view.service.DownloadService
import com.lsp.view.ui.compose.screen.DetailScreen
import com.lsp.view.ui.compose.screen.PostListScreen
import moe.uni.view.service.DownloadService
import moe.uni.view.ui.compose.screen.DetailScreen
import moe.uni.view.ui.compose.screen.PostListScreen
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -1,8 +1,8 @@
package com.lsp.view.ui.compose
package moe.uni.view.ui.compose
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import com.lsp.view.bean.Post
import moe.uni.view.bean.Post
data class PostUiState(
var refresh:MutableState<Boolean> = mutableStateOf(true),
@@ -1,12 +1,12 @@
package com.lsp.view.ui.compose
package moe.uni.view.ui.compose
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.lsp.view.bean.YandPost
import com.lsp.view.repository.exception.NetworkErrorException
import com.lsp.view.repository.network.PostRepository
import com.lsp.view.service.Result
import moe.uni.view.bean.YandPost
import moe.uni.view.repository.exception.NetworkErrorException
import moe.uni.view.repository.network.PostRepository
import moe.uni.view.service.Result
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -1,4 +1,4 @@
package com.lsp.view.ui.compose.screen
package moe.uni.view.ui.compose.screen
import android.widget.Toast
import androidx.compose.foundation.background
@@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Share
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -29,10 +30,10 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.navigation.NavController
import coil.compose.AsyncImage
import com.lsp.view.R
import com.lsp.view.common.setWallpaper
import com.lsp.view.common.share
import com.lsp.view.ui.compose.PostViewModel
import moe.uni.view.R
import moe.uni.view.common.setWallpaper
import moe.uni.view.common.share
import moe.uni.view.ui.compose.PostViewModel
@OptIn(ExperimentalMaterial3Api::class)
@@ -77,7 +78,7 @@ fun DetailScreen(navController: NavController, viewModel: PostViewModel) {
title = {},
navigationIcon = {
IconButton(onClick = { navController.popBackStack() }) {
Icon(imageVector = Icons.Filled.ArrowBack, contentDescription = R.string.description_back.toString())
Icon(imageVector = Icons.AutoMirrored.Default.ArrowBack, contentDescription = R.string.description_back.toString())
}
},
actions = {
@@ -1,4 +1,4 @@
package com.lsp.view.ui.compose.screen
package moe.uni.view.ui.compose.screen
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
@@ -53,11 +53,11 @@ import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import coil.compose.SubcomposeAsyncImage
import coil.compose.SubcomposeAsyncImageContent
import com.lsp.view.bean.Post
import com.lsp.view.common.Config
import com.lsp.view.ui.compose.NAV_ROUTE_DETAIL_SCREEN
import com.lsp.view.ui.compose.PostViewModel
import com.lsp.view.ui.compose.widget.SearchBar
import moe.uni.view.bean.Post
import moe.uni.view.common.Config
import moe.uni.view.ui.compose.NAV_ROUTE_DETAIL_SCREEN
import moe.uni.view.ui.compose.PostViewModel
import moe.uni.view.ui.compose.widget.SearchBar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
@@ -1,4 +1,4 @@
package com.lsp.view.ui.compose.theme
package moe.uni.view.ui.compose.theme
import androidx.compose.ui.graphics.Color
@@ -1,4 +1,4 @@
package com.lsp.view.ui.compose.theme
package moe.uni.view.ui.compose.theme
import android.app.Activity
import android.os.Build
@@ -1,4 +1,4 @@
package com.lsp.view.ui.compose.theme
package moe.uni.view.ui.compose.theme
import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
@@ -1,4 +1,4 @@
package com.lsp.view.ui.compose.widget
package moe.uni.view.ui.compose.widget
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@@ -1,5 +0,0 @@
<?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>
@@ -1,5 +0,0 @@
<?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>
-31
View File
@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
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=".ui.activity.MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:layout_gravity="bottom"
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/nav_menu" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
@@ -1,10 +0,0 @@
<?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=".ui.fragment.CollectFragment">
<include layout="@layout/post_list_layout"/>
</FrameLayout>
@@ -1,38 +0,0 @@
<?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=".ui.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>
-38
View File
@@ -1,38 +0,0 @@
<?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>
@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
android:elevation="20dp"
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:cardCornerRadius="4dp"
android:layout_margin="5dp"
style="?attr/materialCardViewElevatedStyle"
android:layout_height="wrap_content">
<FrameLayout
android:id="@+id/item_pic"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:id="@+id/image"/>
</FrameLayout>
</com.google.android.material.card.MaterialCardView>
@@ -1,17 +0,0 @@
<?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,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
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"
/>
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
android:id="@+id/settings"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_margin="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tag"/>
</com.google.android.material.card.MaterialCardView>
@@ -1,15 +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: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>
-17
View File
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="@+id/postListFragment"
android:icon="@drawable/ic_baseline_insert_photo_24"
android:title="@string/item_gallery"/>
<item
android:id="@+id/collectFragment"
android:icon="@drawable/ic_baseline_favorite_24"
android:title="@string/item_collect"/>
<item
android:id="@+id/settingsFragment"
android:icon="@drawable/baseline_settings_24"
android:title="@string/item_settings"/>
</group>
</menu>
-44
View File
@@ -1,44 +0,0 @@
<?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.ui.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>
</fragment>
<fragment
android:id="@+id/imageFragment"
android:name="com.lsp.view.ui.fragment.ImageFragment"
android:label="fragment_pic"
tools:layout="@layout/fragment_image" >
</fragment>
<fragment
android:id="@+id/collectFragment"
android:name="com.lsp.view.ui.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>
<fragment
android:id="@+id/settingsFragment"
android:name="com.lsp.view.ui.fragment.SettingsFragment"
android:label="SettingsFragment" />
</navigation>
+2 -2
View File
@@ -6,9 +6,9 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.3.1'
classpath 'com.android.tools.build:gradle:8.3.2'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10'
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.7.5"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.7.7"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
+1 -1
View File
@@ -1,2 +1,2 @@
include ':app'
rootProject.name = "LspView"
rootProject.name = "YandView"