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

23-Kotlin #29

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
11 changes: 11 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,21 @@ android {
kotlinOptions {
jvmTarget = '1.8'
}
viewBinding {
enabled true
}

}


dependencies {

implementation("io.coil-kt:coil:2.0.0-rc03")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1")
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0"
implementation "androidx.recyclerview:recyclerview:1.2.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'
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?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" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
Expand All @@ -10,7 +10,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,7 @@
package com.github.krottv.tmstemp.data

import com.github.krottv.tmstemp.domain.PostModel

interface PostsRemoteDataSource {
suspend fun getPosts(): List<PostModel>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.github.krottv.tmstemp.data

import com.github.krottv.tmstemp.domain.PostModel
import kotlinx.coroutines.delay

class PostsRemoteDataSourceFake : PostsRemoteDataSource {

override suspend fun getPosts(): List<PostModel> {
delay(2000L)

val model = PostModel(
"https://images.unsplash.com/photo-1568127861543-b0c0696c735f?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=470&q=80",
"Пункт", "Какой-то текст Какой-то текст Какой-то текст Какой-то текст")

val mutableListOf = ArrayList<PostModel>(1000)

for (i in 0..1000) {
mutableListOf.add(model.copy(title = "${model.title} $i")) }
return mutableListOf
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.github.krottv.tmstemp.data

import com.github.krottv.tmstemp.domain.PostModel
import kotlinx.coroutines.delay

class PostsRemoteDataSourceFakeError : PostsRemoteDataSource {
override suspend fun getPosts(): List<PostModel> {
delay(2000L)
throw Exception("Error")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.github.krottv.tmstemp.domain

data class PostModel(val image: String,
val title: String,
val subtitle: String)
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.domain.PostModel
import com.github.krottv.tmstemp.data.PostsRemoteDataSource
import com.github.krottv.tmstemp.data.PostsRemoteDataSourceFake
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

class PostViewModel : ViewModel() {
private val postsRemoteDataSourse: PostsRemoteDataSource = PostsRemoteDataSourceFake()

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

fun loadData() {
viewModelScope.launch(Dispatchers.IO) {
val result = try {
Result.success(postsRemoteDataSourse.getPosts())
} catch (t: Throwable) {
Result.failure(t)
}
_state.emit(result)
}
}
}
38 changes: 38 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,38 @@
package com.github.krottv.tmstemp.view

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.github.krottv.tmstemp.presentation.PostViewModel
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {

lateinit var viewModel: PostViewModel

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

viewModel = ViewModelProvider(this)[PostViewModel::class.java]

val mainActivityBinder = MainActivityBinder(this)
mainActivityBinder.bindView()

viewModel.loadData()

lifecycleScope.launch {
viewModel.state.collect {
if (it != null) {
if (it.isSuccess) {
mainActivityBinder.PostsScene()
mainActivityBinder.onDataLoaded(it.getOrThrow())
}
if (it.isFailure) {
mainActivityBinder.ErrorScene(it.exceptionOrNull() as Throwable)
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.github.krottv.tmstemp.view

import android.app.Activity
import android.view.LayoutInflater

import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.*
import androidx.transition.Scene
import androidx.transition.TransitionManager
import com.github.krottv.tmstemp.R
import com.github.krottv.tmstemp.databinding.ActivityMainBinding
import com.github.krottv.tmstemp.domain.PostModel

class MainActivityBinder(val activity: Activity) {

private lateinit var binding: RecyclerView
private lateinit var rootScene: ActivityMainBinding
private lateinit var loadScene: Scene
private lateinit var postsScene: Scene

fun bindView() {
rootScene = ActivityMainBinding.inflate(LayoutInflater.from(activity))
activity.setContentView(rootScene.root)
LoadScene()
activity.findViewById<TextView>(R.id.btDelete)
.setOnClickListener {
(binding.adapter as PostsAdapter).removeFirstItem()
}
}

private fun LoadScene() {
loadScene = Scene.getSceneForLayout(rootScene.sceneRoot, R.layout.progress_bar, activity)
TransitionManager.go(loadScene)
}

fun PostsScene() {
postsScene = Scene.getSceneForLayout(rootScene.sceneRoot, R.layout.recyclerview_scene, activity)
TransitionManager.go(postsScene)
binding = rootScene.sceneRoot.findViewById(R.id.View)
val layoutManger = LinearLayoutManager(activity, VERTICAL, false)
binding.layoutManager = layoutManger
}

fun ErrorScene(e: Throwable) {
val errorScene =
Scene.getSceneForLayout(rootScene.sceneRoot, R.layout.error_layout, activity)
TransitionManager.go(errorScene)
val error = rootScene.sceneRoot.findViewById<TextView>(R.id.error)
error.text = e.message
}

fun onDataLoaded(list: List<PostModel>) {
if (binding.adapter == null) {
binding.adapter = PostsAdapter(list)
} else {
(binding.adapter as PostsAdapter).data = list as MutableList<PostModel>
}
}
}
14 changes: 14 additions & 0 deletions app/src/main/java/com/github/krottv/tmstemp/view/PostViewHolder.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.github.krottv.tmstemp.view

import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.github.krottv.tmstemp.R

class PostViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val image1 = view.findViewById<ImageView>(R.id.imageView1)
val textView1 = view.findViewById<TextView>(R.id.textView1)
val textView2 = view.findViewById<TextView>(R.id.textView2)
val image2 = view.findViewById<ImageView>(R.id.imageView2)
}
35 changes: 35 additions & 0 deletions app/src/main/java/com/github/krottv/tmstemp/view/PostsAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.github.krottv.tmstemp.view

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import coil.load
import com.github.krottv.tmstemp.R
import com.github.krottv.tmstemp.domain.PostModel

class PostsAdapter(data: List<PostModel>) : RecyclerView.Adapter<PostViewHolder>() {

var data: MutableList<PostModel> = data as MutableList<PostModel>

fun removeFirstItem() {
data.removeAt(0)
notifyItemRemoved(0)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PostViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_post, parent, false)
return PostViewHolder(view)
}

override fun onBindViewHolder(holder: PostViewHolder, position: Int) {
val item = data[position]
holder.image1.load(item.image)
holder.textView1.text = item.title
holder.textView2.text = item.subtitle
holder.image2.load(item.image)
}

override fun getItemCount(): Int {
return data.size
}
}
34 changes: 26 additions & 8 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,33 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
tools:context=".view.MainActivity">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"

<FrameLayout
android:id="@+id/scene_root"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/btDelete"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/btDelete"
android:layout_width="0dp"
android:layout_height="52dp"
android:layout_marginStart="25dp"
android:layout_marginEnd="23dp"
android:layout_marginBottom="15dp"
android:background="#2F80ED "
android:text="Удалить один"
android:gravity="center"
android:textAlignment="center"
android:textColor="#FFFFFF"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
16 changes: 16 additions & 0 deletions app/src/main/res/layout/error_layout.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/Error"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:id="@+id/error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
52 changes: 52 additions & 0 deletions app/src/main/res/layout/item_post.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content">

<ImageView
android:id="@+id/imageView1"
android:layout_width="58dp"
android:layout_height="58dp"
android:layout_marginStart="16dp"
android:layout_marginTop="12dp"
android:scaleType="centerCrop"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="@tools:sample/avatars" />

<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="21dp"
android:textStyle="bold"
app:layout_constraintStart_toEndOf="@+id/imageView1"
app:layout_constraintTop_toTopOf="@+id/imageView1" />

<TextView
android:id="@+id/textView2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="21dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="46dp"
android:textSize="11sp"
app:layout_constraintEnd_toStartOf="@+id/imageView2"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/imageView1"
app:layout_constraintTop_toBottomOf="@+id/textView1" />

<ImageView
android:id="@+id/imageView2"
tools:srcCompat="@tools:sample/avatars"
android:layout_width="33dp"
android:layout_height="33dp"
android:layout_marginEnd="17dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="@+id/imageView1"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Loading