Skip to content

Commit 10807b5

Browse files
committed
Bug fixes
1 parent cf23b71 commit 10807b5

14 files changed

+814
-270
lines changed

.idea/deploymentTargetDropDown.xml

+7-22
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/gradle.xml

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/build.gradle.kts

+9-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ android {
1212

1313
defaultConfig {
1414
applicationId = "com.rajat.sample.pdfviewer"
15-
minSdk = 21
15+
minSdk = 24
1616
targetSdk = 34
1717
versionCode = 2
1818
versionName = "1.1"
@@ -72,7 +72,7 @@ dependencies {
7272
implementation("androidx.core:core-ktx:1.12.0")
7373
implementation("androidx.appcompat:appcompat:1.6.1")
7474
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
75-
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
75+
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
7676
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
7777
implementation("androidx.compose.ui:ui-graphics")
7878
testImplementation("junit:junit:4.13.2")
@@ -84,6 +84,8 @@ dependencies {
8484
androidTestImplementation("androidx.test:rules:1.5.0")
8585
androidTestImplementation("androidx.test.ext:junit-ktx:1.1.5")
8686

87+
implementation("androidx.recyclerview:recyclerview:1.3.2") // Check for the latest version available
88+
8789
// compose
8890
implementation(platform("androidx.compose:compose-bom:2023.10.01"))
8991
androidTestImplementation(platform("androidx.compose:compose-bom:2023.10.01"))
@@ -107,8 +109,12 @@ dependencies {
107109
// UI Tests
108110
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
109111
debugImplementation("androidx.compose.ui:ui-test-manifest")
112+
androidTestImplementation("androidx.test.ext:junit:1.1.5")
113+
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
114+
110115

111116
// Optional - Integration with activities
112-
implementation("androidx.activity:activity-compose:1.8.1")
117+
implementation("androidx.activity:activity-compose:1.8.2")
118+
113119

114120
}

app/src/main/java/com/rajat/sample/pdfviewer/MainActivity.kt

+36-2
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ class MainActivity : AppCompatActivity() {
1717
private lateinit var binding: ActivityMainBinding
1818

1919
private var download_file_url = "https://css4.pub/2015/usenix/example.pdf"
20+
private var large_pdf = "https://research.nhm.org/pdfs/10840/10840.pdf"
2021
private var download_file_url1 = "https://css4.pub/2017/newsletter/drylab.pdf"
2122
private var download_file_url2 = "https://css4.pub/2015/textbook/somatosensory.pdf"
22-
private var download_file_url3 = "https://file-examples.com/storage/fe19e15eac6560f8c936c41/2017/10/file-example_PDF_1MB.pdf"
2323

2424
override fun onCreate(savedInstanceState: Bundle?) {
2525
super.onCreate(savedInstanceState)
@@ -28,7 +28,39 @@ class MainActivity : AppCompatActivity() {
2828
setContentView(view)
2929

3030
binding.onlinePdf.setOnClickListener {
31-
launchPdfFromUrl(download_file_url)
31+
binding.pdfView.statusListener = object : PdfRendererView.StatusCallBack {
32+
override fun onPdfLoadStart() {
33+
Log.i("statusCallBack","onPdfLoadStart")
34+
}
35+
override fun onPdfLoadProgress(
36+
progress: Int,
37+
downloadedBytes: Long,
38+
totalBytes: Long?
39+
) {
40+
//Download is in progress
41+
}
42+
43+
override fun onPdfLoadSuccess(absolutePath: String) {
44+
Log.i("statusCallBack","onPdfLoadSuccess")
45+
// binding.pdfView.recyclerView.scrollToPosition(1)
46+
binding.pdfView.post {
47+
binding.pdfView.recyclerView.scrollToPosition(
48+
1
49+
)
50+
}
51+
52+
}
53+
54+
override fun onError(error: Throwable) {
55+
Log.i("statusCallBack","onError")
56+
}
57+
58+
override fun onPageChanged(currentPage: Int, totalPage: Int) {
59+
//Page change. Not require
60+
}
61+
}
62+
63+
launchPdfFromUrl(large_pdf)
3264
}
3365

3466
binding.pickPdfButton.setOnClickListener {
@@ -69,6 +101,8 @@ class MainActivity : AppCompatActivity() {
69101
lifecycleCoroutineScope = lifecycleScope,
70102
lifecycle = lifecycle
71103
)
104+
binding.pdfView.jumpToPage(3)
105+
72106
}
73107

74108
binding.openInCompose.setOnClickListener {

gradle.properties

-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,5 @@ android.useAndroidX=true
1919
android.enableJetifier=true
2020
# Kotlin code style for this project: "official" or "obsolete":
2121
kotlin.code.style=official
22-
android.defaults.buildfeatures.buildconfig=true
2322
android.nonTransitiveRClass=false
2423
android.nonFinalResIds=false

pdfViewer/build.gradle.kts

+47-15
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1+
import com.vanniktech.maven.publish.AndroidSingleVariantLibrary
2+
import com.vanniktech.maven.publish.SonatypeHost
3+
14
plugins {
25
id("com.android.library")
36
id("org.jetbrains.kotlin.android")
47
id("kotlin-parcelize")
5-
id("maven-publish")
8+
id("org.jetbrains.dokka") version "1.9.20"
9+
id("com.vanniktech.maven.publish") version "0.28.0"
610
}
711

812
android {
913
namespace = "com.rajat.pdfviewer"
1014
compileSdk = 34
1115

1216
defaultConfig {
13-
minSdk = 21
17+
minSdk = 24
1418
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
1519
consumerProguardFiles("consumer-rules.pro")
1620
}
@@ -56,7 +60,7 @@ dependencies {
5660
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
5761
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
5862
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
59-
implementation("com.google.android.material:material:1.10.0")
63+
implementation("com.google.android.material:material:1.11.0")
6064
testImplementation("junit:junit:4.13.2")
6165
androidTestImplementation("androidx.test.ext:junit:1.1.5")
6266
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
@@ -66,25 +70,53 @@ dependencies {
6670
// compose
6771
implementation(platform("androidx.compose:compose-bom:2023.10.01"))
6872
androidTestImplementation(platform("androidx.compose:compose-bom:2023.10.01"))
69-
implementation("androidx.compose.ui:ui")
73+
implementation("androidx.compose.ui:ui:1.6.4")
7074
// Android Studio Preview support
71-
implementation("androidx.compose.ui:ui-tooling-preview")
72-
debugImplementation("androidx.compose.ui:ui-tooling")
75+
implementation("androidx.compose.ui:ui-tooling-preview:1.6.4")
76+
debugImplementation("androidx.compose.ui:ui-tooling:1.6.4")
7377
// UI Tests
7478
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
7579
debugImplementation("androidx.compose.ui:ui-test-manifest")
76-
implementation("androidx.activity:activity-compose:1.8.1")
80+
implementation("androidx.activity:activity-compose:1.8.2")
7781
}
7882

79-
publishing {
80-
publications {
81-
register<MavenPublication>("release") {
82-
groupId = "com.rajat"
83-
artifactId = "pdfviewer"
84-
version = "2.0"
85-
afterEvaluate {
86-
from(components["release"])
83+
mavenPublishing {
84+
configure(
85+
AndroidSingleVariantLibrary(
86+
// the published variant
87+
variant = "release",
88+
// whether to publish a sources jar
89+
sourcesJar = true,
90+
)
91+
)
92+
93+
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
94+
signAllPublications()
95+
96+
coordinates("io.github.afreakyelf", "Pdf-Viewer", "2.1.0")
97+
98+
pom {
99+
name.set("PDF Viewer")
100+
description.set("A PDF viewing library for Android")
101+
url.set("https://github.com/afreakyelf/pdfviewer")
102+
licenses {
103+
license {
104+
name.set("MIT License")
105+
url.set("https://opensource.org/licenses/MIT")
87106
}
88107
}
108+
developers {
109+
developer {
110+
id.set("afreakyelf")
111+
name.set("Rajat Mittal")
112+
email.set("[email protected]")
113+
}
114+
}
115+
scm {
116+
connection.set("scm:git:git://github.com/afreakyelf/pdfviewer.git")
117+
developerConnection.set("scm:git:ssh://github.com/afreakyelf/pdfviewer.git")
118+
url.set("https://github.com/afreakyelf/pdfviewer")
119+
}
89120
}
121+
90122
}

pdfViewer/src/main/java/com/rajat/pdfviewer/PdfDownloader.kt

+56-29
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package com.rajat.pdfviewer
22

33
import android.content.Context
4+
import android.util.Log
45
import kotlinx.coroutines.CoroutineScope
56
import kotlinx.coroutines.Dispatchers
7+
import kotlinx.coroutines.delay
68
import kotlinx.coroutines.launch
79
import kotlinx.coroutines.withContext
810
import java.io.BufferedInputStream
911
import java.io.File
12+
import java.io.FileOutputStream
13+
import java.io.IOException
1014
import java.net.URL
1115

1216
class PdfDownloader(
@@ -30,6 +34,11 @@ class PdfDownloader(
3034
coroutineScope.launch { checkAndDownload(url) }
3135
}
3236

37+
companion object {
38+
private const val MAX_RETRIES = 3 // Maximum number of retries
39+
private const val RETRY_DELAY = 2000L // Delay between retries in milliseconds
40+
}
41+
3342
private fun getCachedFileName(url: String): String {
3443
return url.hashCode().toString() + ".pdf"
3544
}
@@ -59,41 +68,59 @@ class PdfDownloader(
5968
}
6069

6170
private suspend fun download(downloadUrl: String, cachedFileName: String) {
62-
withContext(Dispatchers.IO) {
63-
try {
64-
listener.onDownloadStart()
65-
val outputFile = File(listener.getContext().cacheDir, cachedFileName)
66-
outputFile.delete()
67-
val urlConnection = URL(downloadUrl).openConnection().apply {
68-
// Apply headers to the URL connection
69-
headers.headers.forEach { (key, value) ->
70-
setRequestProperty(key, value)
71+
var retries = 0
72+
while (retries < MAX_RETRIES) {
73+
withContext(Dispatchers.IO) {
74+
var tempFile: File? = null
75+
try {
76+
listener.onDownloadStart()
77+
val cacheDir = listener.getContext().cacheDir
78+
tempFile = File.createTempFile("download_", ".tmp", cacheDir)
79+
val urlConnection = URL(downloadUrl).openConnection().apply {
80+
headers.headers.forEach { (key, value) -> setRequestProperty(key, value) }
7181
}
72-
}
73-
val totalLength = urlConnection.contentLength
74-
BufferedInputStream(urlConnection.getInputStream()).use { inputStream ->
75-
outputFile.outputStream().use { outputStream ->
76-
val data = ByteArray(8192)
77-
var totalBytesRead = 0L
78-
var bytesRead: Int
79-
80-
while (inputStream.read(data).also { bytesRead = it } != -1) {
81-
outputStream.write(data, 0, bytesRead)
82-
totalBytesRead += bytesRead
83-
withContext(Dispatchers.Main) {
84-
listener.onDownloadProgress(totalBytesRead, totalLength.toLong())
82+
val totalLength = urlConnection.contentLengthLong
83+
BufferedInputStream(urlConnection.getInputStream()).use { inputStream ->
84+
FileOutputStream(tempFile).use { outputStream ->
85+
val data = ByteArray(8192)
86+
var totalBytesRead = 0L
87+
var bytesRead: Int
88+
while (inputStream.read(data).also { bytesRead = it } != -1) {
89+
outputStream.write(data, 0, bytesRead)
90+
totalBytesRead += bytesRead
91+
withContext(Dispatchers.Main) {
92+
listener.onDownloadProgress(totalBytesRead, totalLength)
93+
}
8594
}
95+
outputStream.flush() // Ensure all data is written to the file
96+
}
97+
}
98+
if (tempFile.length() == totalLength) {
99+
val outputFile = File(cacheDir, cachedFileName)
100+
tempFile.renameTo(outputFile)
101+
withContext(Dispatchers.Main) { listener.onDownloadSuccess(outputFile.absolutePath) }
102+
retries = MAX_RETRIES
103+
return@withContext
104+
} else {
105+
throw IOException("Incomplete download")
106+
}
107+
} catch (e: IOException) {
108+
tempFile?.delete()
109+
Log.e("PdfDownloader", "Download incomplete or failed: $downloadUrl", e)
110+
withContext(Dispatchers.Main) { listener.onError(e) }
111+
retries++
112+
if (retries < MAX_RETRIES) {
113+
Log.d("PdfDownloader", "Retrying download: $downloadUrl. Attempt $retries")
114+
delay(RETRY_DELAY) // Backoff before retrying
115+
} else {
116+
withContext(Dispatchers.Main) {
117+
listener.onError(IOException("Failed to download after $MAX_RETRIES attempts: $downloadUrl", e))
86118
}
87119
}
88120
}
89-
withContext(Dispatchers.Main) {
90-
listener.onDownloadSuccess(outputFile.absolutePath)
91-
}
92-
} catch (e: Exception) {
93-
withContext(Dispatchers.Main) {
94-
listener.onError(e)
95-
}
121+
96122
}
97123
}
98124
}
125+
99126
}

0 commit comments

Comments
 (0)