Skip to content
This repository has been archived by the owner on Aug 7, 2024. It is now read-only.

25-Kotlin #37

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'androidx.navigation.safeargs.kotlin'
}

android {
compileSdk 31

viewBinding {
enabled = true
}

defaultConfig {
applicationId "com.github.krottv.tmstemp"
minSdk 24
Expand Down Expand Up @@ -33,9 +38,21 @@ android {

dependencies {

implementation "androidx.navigation:navigation-fragment-ktx:2.4.2"
implementation "androidx.navigation:navigation-ui-ktx:2.4.2"
implementation "androidx.fragment:fragment-ktx:1.4.1"
implementation "androidx.activity:activity-ktx:1.4.0"

implementation "io.coil-kt:coil:2.0.0-rc03"

implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1'

implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'com.google.android.material:material:1.6.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
Expand Down
4 changes: 3 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.krottv.tmstemp">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<application
android:allowBackup="true"
Expand All @@ -10,7 +12,7 @@
android:supportsRtl="true"
android:theme="@style/Theme.TmsTemp">
<activity
android:name=".MainActivity"
android:name=".view.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.github.krottv.tmstemp.binder

interface MainActivityDataBinder {
fun bind()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.github.krottv.tmstemp.binder
import android.app.Activity
import android.view.LayoutInflater
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupWithNavController
import com.github.krottv.tmstemp.databinding.ActivityMainBinding


class MainActivityRecyclerScrollDataBinder(private val activity: Activity): MainActivityDataBinder {

override fun bind() {
val container = ActivityMainBinding.inflate(LayoutInflater.from(activity))

val navController = container.navHostFragment.getFragment<Fragment>().findNavController()
val appBarConfiguration = AppBarConfiguration(navController.graph)

container.toolbar.setupWithNavController(navController, appBarConfiguration)
activity.setContentView(container.root)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.github.krottv.tmstemp.binder

import android.os.Bundle
import android.transition.*
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.github.krottv.tmstemp.R
import com.github.krottv.tmstemp.databinding.SceneContainerBinding
import com.github.krottv.tmstemp.domain.MessageModel
import com.github.krottv.tmstemp.view.MessageAdapter

class RecyclerFragmentBinder(private val fragment: Fragment, private val onItemClick: (View, MessageModel) -> Unit) {

private lateinit var binding: SceneContainerBinding

fun bindView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = SceneContainerBinding.inflate(inflater, container, false)

return binding.root
}


private val customTransition = TransitionSet().apply {
addTransition(ChangeBounds())
addTransition(Fade(Fade.IN))
}

fun onDataLoaded(data: List<MessageModel>) {

val scene = Scene.getSceneForLayout(binding.sceneRoot, R.layout.fragment, fragment.requireContext())
TransitionManager.go(scene, customTransition)

val recyclerView = scene.sceneRoot.findViewById<RecyclerView>(R.id.container)
recyclerView.layoutManager = LinearLayoutManager(fragment.requireContext())

if (recyclerView.adapter == null) {
recyclerView.adapter = MessageAdapter(data, onItemClick)
} else {
(recyclerView.adapter as MessageAdapter).data = data
}
}

fun showError(exception: Throwable) {

val scene = Scene.getSceneForLayout(binding.sceneRoot, R.layout.error, fragment.requireContext())
TransitionManager.go(scene, customTransition)

scene.sceneRoot.findViewById<TextView>(R.id.errorText).apply {
text = exception.message
}
}

fun showProgress() {

val scene = Scene.getSceneForLayout(binding.sceneRoot, R.layout.progress_bar, fragment.requireContext())
TransitionManager.go(scene, customTransition)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.github.krottv.tmstemp.data

import com.github.krottv.tmstemp.domain.MessageModel

interface RemoteDataSource {
suspend fun getMessages(): List<MessageModel>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.github.krottv.tmstemp.data

import com.github.krottv.tmstemp.domain.MessageModel
import kotlinx.coroutines.delay
import java.lang.IllegalStateException

class RemoteDataSourceError: RemoteDataSource {
override suspend fun getMessages(): List<MessageModel> {
delay(2000)
throw IllegalStateException("IllegalStateException")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.github.krottv.tmstemp.data
import com.github.krottv.tmstemp.domain.MessageModel
import kotlinx.coroutines.delay

class RemoteDataSourceFake: RemoteDataSource {

companion object {
const val MESSAGES_COUNT = 1000
}
override suspend fun getMessages(): List<MessageModel> {
delay(2000)
val message = MessageModel(
"https://images.unsplash.com/photo-1568127861543-b0c0696c735f?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=470&q=80",
"Пользователь",
"Какой-то текст Какой-то текст Какой-то текст Какой-то текст"
)
val result = ArrayList<MessageModel>(MESSAGES_COUNT)
for (i in 0..MESSAGES_COUNT) {
result.add(message.copy(mainText = "Пользователь $i"))
}
return result
}
}
35 changes: 35 additions & 0 deletions app/src/main/java/com/github/krottv/tmstemp/domain/MessageModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.github.krottv.tmstemp.domain
import android.os.Parcel
import android.os.Parcelable
import androidx.annotation.Keep

@Keep
data class MessageModel(val mainImage: String, val mainText: String, val littleText: String): Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString()!!,
parcel.readString()!!,
parcel.readString()!!
)

fun transitionId() = mainText + "_"

override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(mainImage)
parcel.writeString(mainText)
parcel.writeString(littleText)
}

override fun describeContents(): Int {
return 0
}

companion object CREATOR : Parcelable.Creator<MessageModel> {
override fun createFromParcel(parcel: Parcel): MessageModel {
return MessageModel(parcel)
}

override fun newArray(size: Int): Array<MessageModel?> {
return arrayOfNulls(size)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.github.krottv.tmstemp.presentation
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.github.krottv.tmstemp.data.RemoteDataSource
import com.github.krottv.tmstemp.data.RemoteDataSourceFake
import com.github.krottv.tmstemp.domain.MessageModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

class MessageViewModel: ViewModel() {
private val fakeMessages: RemoteDataSource = RemoteDataSourceFake()

private val _state = MutableStateFlow<Result<List<MessageModel>>?>(null)
val state: StateFlow<Result<List<MessageModel>>?> = _state

fun loadData() {
viewModelScope.launch(Dispatchers.IO) {
val result = try {
Result.success(fakeMessages.getMessages())
} catch (exception: Throwable) {
Result.failure(exception)
}

_state.emit(result)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.github.krottv.tmstemp.view
import android.animation.ObjectAnimator
import android.animation.PropertyValuesHolder
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.LinearInterpolator
import android.widget.ImageView
import androidx.core.view.doOnPreDraw
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.transition.AutoTransition
import coil.load
import com.github.krottv.tmstemp.databinding.FullscreenBinding


import com.github.krottv.tmstemp.domain.MessageModel
import java.util.concurrent.TimeUnit

class FullscreenFragment: Fragment() {

companion object {
const val TRANSITION_ID = "Fullscreen"
}

private lateinit var binding: FullscreenBinding

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
sharedElementEnterTransition = AutoTransition()
sharedElementReturnTransition = AutoTransition()

binding = FullscreenBinding.inflate(inflater, container, false)

binding.root.transitionName = TRANSITION_ID

return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

val item: MessageModel = requireArguments().getParcelable("currentMessage")!!

postponeEnterTransition(3000, TimeUnit.MILLISECONDS)

binding.someText.text = item.littleText

binding.imageView.load(item.mainImage) {
listener { request, result ->
(view.parent as? View)?.doOnPreDraw {
startPostponedEnterTransition()
}
}
}

binding.imageView.scaleType = ImageView.ScaleType.CENTER_CROP

ObjectAnimator().apply {
target = binding.buttonClose
duration = 500
repeatCount = ObjectAnimator.INFINITE
repeatMode = ObjectAnimator.REVERSE
interpolator = LinearInterpolator()
setValues(PropertyValuesHolder.ofFloat("scaleX", 1f, 1.2f),
PropertyValuesHolder.ofFloat("scaleY", 1f, 1.2f))
start()
}

binding.buttonClose.setOnClickListener {
findNavController().navigateUp()
}
}
}
14 changes: 14 additions & 0 deletions app/src/main/java/com/github/krottv/tmstemp/view/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.github.krottv.tmstemp.view
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.github.krottv.tmstemp.binder.MainActivityDataBinder
import com.github.krottv.tmstemp.binder.MainActivityRecyclerScrollDataBinder

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

val mainActivityDataBinder: MainActivityDataBinder = MainActivityRecyclerScrollDataBinder(this)
mainActivityDataBinder.bind()
}
}
Loading