Compare commits

...

2 Commits

10 changed files with 207 additions and 0 deletions

1
pdf-viewer/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

40
pdf-viewer/build.gradle Normal file
View File

@ -0,0 +1,40 @@
plugins {
id 'com.android.library'
id 'org.jetbrains.kotlin.android'
}
android {
compileSdk 31
defaultConfig {
minSdk 23
targetSdk 31
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

View File

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="ru.touchin.roboswag.pdf_viewer"> </manifest>

View File

@ -0,0 +1,24 @@
package ru.touchin.roboswag.pdf_reader.extensions
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.pdf.PdfRenderer
fun PdfRenderer.Page.renderBitmap(width: Int) = use {
val bitmap = createBitmap(width)
render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
bitmap
}
private fun PdfRenderer.Page.createBitmap(bitmapWidth: Int): Bitmap {
val bitmap = Bitmap.createBitmap(
bitmapWidth, (bitmapWidth.toFloat() / width * height).toInt(), Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
canvas.drawColor(Color.WHITE)
canvas.drawBitmap(bitmap, 0f, 0f, null)
return bitmap
}

View File

@ -0,0 +1,10 @@
package ru.touchin.roboswag.pdf_reader.repository
import android.graphics.Bitmap
import java.io.File
interface PdfViewRepository {
suspend fun renderSinglePage(filePath: String, width: Int) : Bitmap
}

View File

@ -0,0 +1,58 @@
package ru.touchin.roboswag.pdf_reader.ui.base
import android.graphics.Bitmap
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.fragment.app.Fragment
import ru.touchin.roboswag.pdf_reader.viewstate.PdfReaderViewState
import ru.touchin.roboswag.pdf_reader.BaseViewModel
import java.io.File
abstract class BaseFragment<VM : BaseViewModel> : Fragment() {
abstract val viewModel: VM
protected open fun renderData(state: PdfReaderViewState) {
when (state) {
is PdfReaderViewState.RenderingSuccess -> renderSuccess(state.data)
is PdfReaderViewState.Error -> renderError(state.error)
is PdfReaderViewState.Loading -> setLoading(true)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.stateLiveData.observe(viewLifecycleOwner) { state ->
renderData(state)
}
}
protected open fun renderSuccess(bitmap: Bitmap) {
setLoading(false)
}
protected open fun renderError(error: Throwable) {
setLoading(false)
error.message?.let { showMessage(it) }
}
protected open fun renderMessage(message: String) {
setLoading(false)
showMessage(message)
}
protected open fun setLoading(isLoading: Boolean) {
}
private fun showMessage(message: String) {
Toast.makeText(
requireContext(),
message,
Toast.LENGTH_LONG
).show()
}
}

View File

@ -0,0 +1,46 @@
package ru.touchin.roboswag.pdf_reader.viewmodel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import ru.touchin.roboswag.pdf_reader.viewstate.PdfReaderViewState
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.launch
abstract class BaseViewModel(
) : ViewModel() {
protected val mStateLiveData = MutableLiveData<PdfReaderViewState>()
val stateLiveData get() = mStateLiveData as LiveData<PdfReaderViewState>
private val viewModelCoroutineScope = CoroutineScope(
Dispatchers.IO
+ SupervisorJob()
+ CoroutineExceptionHandler { _, throwable ->
handleError(throwable)
})
override fun onCleared() {
super.onCleared()
cancelJob()
}
protected open fun cancelJob() {
viewModelCoroutineScope.coroutineContext.cancelChildren()
}
private fun handleError(error: Throwable) {
mStateLiveData.postValue(PdfReaderViewState.Error(error))
}
protected fun runAsync(block: suspend () -> Unit) =
viewModelCoroutineScope.launch {
block()
}
}

View File

@ -0,0 +1,16 @@
package ru.touchin.roboswag.pdf_reader.viewmodel
import ru.touchin.roboswag.pdf_reader.viewstate.PdfReaderViewState
import ru.touchin.roboswag.pdf_reader.repository.PdfViewRepository
class PdfViewModel(private val repository: PdfViewRepository) : BaseViewModel() {
fun renderPage(filePath: String, width: Int) {
mStateLiveData.postValue(PdfReaderViewState.Loading(true))
runAsync {
val bitmap = repository.renderSinglePage(filePath, width)
mStateLiveData.postValue(PdfReaderViewState.RenderingSuccess(bitmap))
}
}
}

View File

@ -0,0 +1,10 @@
package ru.touchin.roboswag.pdf_reader.viewstate
import android.graphics.Bitmap
import java.io.File
sealed class PdfReaderViewState {
data class RenderingSuccess(val data: Bitmap) : PdfReaderViewState()
data class Error(val error: Throwable) : PdfReaderViewState()
data class Loading(val isLoading: Boolean) : PdfReaderViewState()
}