Skip to content

Commit fdd2bd6

Browse files
sanjay-miakashmimilanvadhel-michiragmiNkgohil007
authored
Develop (#52)
- ANR issue resolved. - Reject permission crash issue resolved. - Library version updated to 0.3.0 - Target SDK version updated, Android 12 support. Co-authored-by: AKASH PATEL <akash.mindinventory@gmail.com> Co-authored-by: milanvadhel-mi <73939866+milanvadhel-mi@users.noreply.github.com> Co-authored-by: Chirag Prajapati <chirag.prajapati@mindinventory.com> Co-authored-by: Nkgohil007 <89060719+Nkgohil007@users.noreply.github.com>
1 parent cf47898 commit fdd2bd6

File tree

16 files changed

+214
-136
lines changed

16 files changed

+214
-136
lines changed

app/build.gradle

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@ apply plugin: 'kotlin-kapt'
55

66

77
android {
8-
compileSdkVersion 30
9-
buildToolsVersion '30.0.3'
8+
compileSdkVersion 32
109
defaultConfig {
1110
applicationId "com.lassi.app"
1211
minSdkVersion 17
13-
targetSdkVersion 30
12+
targetSdkVersion 32
1413
versionCode 1
1514
versionName "1.0"
1615
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -36,10 +35,9 @@ android {
3635

3736
dependencies {
3837
implementation fileTree(dir: 'libs', include: ['*.jar'])
39-
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
40-
implementation 'androidx.appcompat:appcompat:1.3.1'
41-
implementation 'androidx.core:core-ktx:1.6.0'
42-
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
38+
implementation 'androidx.appcompat:appcompat:1.4.1'
39+
implementation 'androidx.core:core-ktx:1.7.0'
40+
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
4341
testImplementation 'junit:junit:4.13.2'
4442
androidTestImplementation 'androidx.test:runner:1.4.0'
4543
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22

33
buildscript {
4-
ext.kotlin_version = '1.5.21'
4+
ext.kotlin_version = '1.6.10'
55
repositories {
66
google()
77
mavenCentral()

gradle/wrapper/gradle-wrapper.jar

100644100755
File mode changed.

lassi/build.gradle

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ apply plugin: 'com.github.dcendents.android-maven'
77
group='com.github.Mindinventory'
88

99
android {
10-
compileSdkVersion 30
10+
compileSdkVersion 32
1111

1212
defaultConfig {
1313
minSdkVersion 17
14-
targetSdkVersion 30
14+
targetSdkVersion 32
1515
versionCode 20
16-
versionName "0.2.2"
16+
versionName "0.3.0"
1717
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1818
vectorDrawables.useSupportLibrary = true
1919
multiDexEnabled true
@@ -47,10 +47,9 @@ android {
4747

4848
dependencies {
4949
implementation fileTree(dir: 'libs', include: ['*.jar'])
50-
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.21'
51-
implementation 'androidx.appcompat:appcompat:1.3.1'
52-
implementation 'androidx.core:core-ktx:1.6.0'
53-
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
50+
implementation 'androidx.appcompat:appcompat:1.4.1'
51+
implementation 'androidx.core:core-ktx:1.7.0'
52+
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
5453
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
5554
implementation "androidx.recyclerview:recyclerview:1.2.1"
5655
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
@@ -62,15 +61,15 @@ dependencies {
6261
implementation 'io.reactivex.rxjava2:rxjava:2.2.21'
6362

6463
// Google material
65-
implementation 'com.google.android.material:material:1.4.0'
64+
implementation 'com.google.android.material:material:1.5.0'
6665

6766
// glide
6867
implementation 'com.github.bumptech.glide:glide:4.12.0'
6968
kapt 'com.github.bumptech.glide:compiler:4.12.0'
7069
implementation 'androidx.exifinterface:exifinterface:1.3.3'
7170

72-
implementation "androidx.activity:activity-ktx:1.3.1"
73-
implementation 'androidx.fragment:fragment-ktx:1.3.6'
71+
implementation "androidx.activity:activity-ktx:1.4.0"
72+
implementation 'androidx.fragment:fragment-ktx:1.4.1'
7473

7574
implementation "androidx.multidex:multidex:2.0.1"
7675
}

lassi/src/main/AndroidManifest.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,21 @@
1212
android:supportsRtl="true">
1313
<activity
1414
android:name=".presentation.mediadirectory.LassiMediaPickerActivity"
15+
android:exported="true"
1516
android:launchMode="singleTask"
1617
android:screenOrientation="portrait"
1718
android:theme="@style/AppTheme" />
1819
<activity
1920
android:name=".presentation.cropper.CropImageActivity"
21+
android:exported="true"
2022
android:resizeableActivity="false"
2123
android:screenOrientation="portrait"
2224
android:supportsPictureInPicture="false"
2325
android:theme="@style/AppTheme"
2426
tools:targetApi="n" />
2527
<activity
2628
android:name=".presentation.videopreview.VideoPreviewActivity"
29+
android:exported="true"
2730
android:screenOrientation="portrait"
2831
android:theme="@style/AppTheme" />
2932
</application>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.lassi.common.extenstions
2+
3+
import com.lassi.data.common.Result
4+
import kotlinx.coroutines.flow.Flow
5+
import kotlinx.coroutines.flow.catch
6+
import kotlin.experimental.ExperimentalTypeInference
7+
8+
@OptIn(ExperimentalTypeInference::class)
9+
fun <T> Flow<Result<T>>.catch(): Flow<Result<T>> {
10+
return this.catch { e ->
11+
emit(Result.Error(e))
12+
}
13+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.lassi.data.common
2+
3+
sealed class Result<out R> {
4+
5+
data class Success<out T>(
6+
val data: T
7+
) : Result<T>()
8+
9+
data class Error(val throwable: Throwable) : Result<Nothing>()
10+
object Loading : Result<Nothing>()
11+
12+
override fun toString(): String {
13+
return when (this) {
14+
is Success<*> -> "Success[data=$data]"
15+
is Error -> "Error[exception=$throwable]"
16+
Loading -> "Loading"
17+
}
18+
}
19+
}

lassi/src/main/java/com/lassi/data/media/MediaRepositoryImpl.kt

Lines changed: 98 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@ import android.os.Build
77
import android.provider.MediaStore
88
import android.webkit.MimeTypeMap
99
import com.lassi.R
10+
import com.lassi.common.extenstions.catch
1011
import com.lassi.common.utils.KeyUtils
1112
import com.lassi.common.utils.Logger
13+
import com.lassi.data.common.Result
1214
import com.lassi.data.mediadirectory.Folder
1315
import com.lassi.domain.media.LassiConfig
1416
import com.lassi.domain.media.MediaRepository
1517
import com.lassi.domain.media.MediaType
16-
import io.reactivex.Single
18+
import kotlinx.coroutines.Dispatchers
19+
import kotlinx.coroutines.flow.Flow
20+
import kotlinx.coroutines.flow.flow
21+
import kotlinx.coroutines.flow.flowOn
1722
import java.io.File
1823
import java.util.*
1924
import kotlin.collections.ArrayList
@@ -27,75 +32,78 @@ class MediaRepositoryImpl(private val context: Context) : MediaRepository {
2732
private val minFileSize = LassiConfig.getConfig().minFileSize * 1024L
2833
private val maxFileSize = LassiConfig.getConfig().maxFileSize * 1024L
2934

30-
@SuppressLint("Range")
31-
override fun fetchFolders(): Single<ArrayList<Folder>> {
32-
val projection = getProjections()
33-
val cursor = query(projection)
34-
cursor ?: return Single.error(Throwable())
35-
folderMap.clear()
36-
fetchedFolders.clear()
37-
try {
38-
if (cursor.moveToLast()) {
39-
do {
40-
val id = cursor.getLong(cursor.getColumnIndex(projection[0]))
41-
val name = cursor.getString(cursor.getColumnIndex(projection[1]))
42-
val path = cursor.getString(cursor.getColumnIndex(projection[2]))
43-
val bucket = cursor.getString(cursor.getColumnIndex(projection[3]))
44-
val size =
45-
cursor.getLong(cursor.getColumnIndex(MediaStore.Files.FileColumns.SIZE))
46-
val albumCoverPath =
47-
if (LassiConfig.getConfig().mediaType == MediaType.AUDIO) {
48-
val albumId = cursor.getString(cursor.getColumnIndex(projection[5]))
49-
if (albumId != null) {
50-
getAlbumArt(albumId)
51-
} else {
52-
continue
53-
}
54-
} else {
55-
""
56-
}
57-
val duration =
58-
if (LassiConfig.getConfig().mediaType == MediaType.VIDEO) {
59-
cursor.getLong(cursor.getColumnIndex(projection[4]))
60-
} else {
61-
0
62-
}
35+
override suspend fun fetchFolders(): Flow<Result<ArrayList<Folder>>> {
36+
return flow {
37+
val projection = getProjections()
38+
val cursor = query(projection)
39+
cursor?.let {
40+
folderMap.clear()
41+
fetchedFolders.clear()
42+
try {
43+
if (cursor.moveToLast()) {
44+
do {
45+
val id = cursor.getLong(cursor.getColumnIndex(projection[0]))
46+
val name = cursor.getString(cursor.getColumnIndex(projection[1]))
47+
val path = cursor.getString(cursor.getColumnIndex(projection[2]))
48+
val bucket = cursor.getString(cursor.getColumnIndex(projection[3]))
49+
val size =
50+
cursor.getLong(cursor.getColumnIndex(MediaStore.Files.FileColumns.SIZE))
51+
val albumCoverPath =
52+
if (LassiConfig.getConfig().mediaType == MediaType.AUDIO) {
53+
val albumId =
54+
cursor.getString(cursor.getColumnIndex(projection[5]))
55+
if (albumId != null) {
56+
getAlbumArt(albumId)
57+
} else {
58+
continue
59+
}
60+
} else {
61+
""
62+
}
63+
val duration =
64+
if (LassiConfig.getConfig().mediaType == MediaType.VIDEO) {
65+
cursor.getLong(cursor.getColumnIndex(projection[4]))
66+
} else {
67+
0
68+
}
6369

64-
val file = makeSafeFile(path)
65-
if (file != null && file.exists()) {
66-
if (LassiConfig.getConfig().mediaType == MediaType.VIDEO ||
67-
LassiConfig.getConfig().mediaType == MediaType.AUDIO
68-
) {
69-
checkDurationAndAddFileToFolder(
70-
bucket,
71-
id,
72-
name,
73-
path,
74-
duration,
75-
albumCoverPath,
76-
size
77-
)
78-
} else {
79-
Logger.e("MediaRepositoryImpl", "$name >> $size")
70+
val file = makeSafeFile(path)
71+
if (file != null && file.exists()) {
72+
if (LassiConfig.getConfig().mediaType == MediaType.VIDEO ||
73+
LassiConfig.getConfig().mediaType == MediaType.AUDIO
74+
) {
75+
checkDurationAndAddFileToFolder(
76+
bucket,
77+
id,
78+
name,
79+
path,
80+
duration,
81+
albumCoverPath,
82+
size
83+
)
84+
} else {
85+
Logger.e("MediaRepositoryImpl", "$name >> $size")
8086

81-
if (isValidFileSize(size)) {
82-
addFileToFolder(
83-
bucket,
84-
MiMedia(id, name, path, duration, albumCoverPath)
85-
)
87+
if (isValidFileSize(size)) {
88+
addFileToFolder(
89+
bucket,
90+
MiMedia(id, name, path, duration, albumCoverPath)
91+
)
92+
}
93+
}
8694
}
87-
}
95+
} while (cursor.moveToPrevious())
8896
}
89-
} while (cursor.moveToPrevious())
90-
}
91-
} catch (e: Exception) {
92-
Logger.e("MediaRepositoryImpl", "fetchFolders >> $e")
93-
return Single.error(e)
94-
} finally {
95-
cursor.close()
96-
}
97-
fetchedFolders.addAll(folderMap.values)
98-
return Single.just(fetchedFolders)
97+
} catch (e: Exception) {
98+
Logger.e("MediaRepositoryImpl", "fetchFolders >> $e")
99+
emit(Result.Error(Throwable()))
100+
} finally {
101+
cursor.close()
102+
}
103+
fetchedFolders.addAll(folderMap.values)
104+
emit(Result.Success(fetchedFolders))
105+
} ?: emit(Result.Error(Throwable()))
106+
}.catch().flowOn(Dispatchers.IO)
99107
}
100108

101109
private fun checkDurationAndAddFileToFolder(
@@ -331,26 +339,29 @@ class MediaRepositoryImpl(private val context: Context) : MediaRepository {
331339
}
332340

333341
@SuppressLint("Range")
334-
override fun fetchDocs(): Single<ArrayList<MiMedia>> {
335-
val projection = getProjections()
336-
val cursor = query(projection)
337-
cursor ?: return Single.error(Throwable())
338-
Logger.e("MediaRepositoryImpl", "Fetch documents size ${cursor.count}")
339-
val docs = ArrayList<MiMedia>()
340-
try {
341-
if (cursor.moveToLast()) {
342-
do {
343-
val id = cursor.getLong(cursor.getColumnIndex(projection[0]))
344-
val name = cursor.getString(cursor.getColumnIndex(projection[1]))
345-
val path = cursor.getString(cursor.getColumnIndex(projection[2]))
346-
docs.add(MiMedia(id, name, path, 0))
347-
} while (cursor.moveToPrevious())
348-
}
349-
} catch (e: Exception) {
350-
Logger.e("MediaRepositoryImpl", "fetchFolders >> $e")
351-
} finally {
352-
cursor.close()
353-
}
354-
return Single.just(docs)
342+
override suspend fun fetchDocs(): Flow<Result<ArrayList<MiMedia>>> {
343+
return flow {
344+
val projection = getProjections()
345+
val cursor = query(projection)
346+
cursor?.let {
347+
Logger.e("MediaRepositoryImpl", "Fetch documents size ${cursor.count}")
348+
val docs = ArrayList<MiMedia>()
349+
try {
350+
if (cursor.moveToLast()) {
351+
do {
352+
val id = cursor.getLong(cursor.getColumnIndex(projection[0]))
353+
val name = cursor.getString(cursor.getColumnIndex(projection[1]))
354+
val path = cursor.getString(cursor.getColumnIndex(projection[2]))
355+
docs.add(MiMedia(id, name, path, 0))
356+
} while (cursor.moveToPrevious())
357+
}
358+
} catch (e: Exception) {
359+
Logger.e("MediaRepositoryImpl", "fetchFolders >> $e")
360+
} finally {
361+
cursor.close()
362+
}
363+
emit(Result.Success(docs))
364+
} ?: emit(Result.Error(Throwable()))
365+
}.catch().flowOn(Dispatchers.IO)
355366
}
356367
}
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package com.lassi.domain.media
22

3+
import com.lassi.data.common.Result
34
import com.lassi.data.media.MiMedia
45
import com.lassi.data.mediadirectory.Folder
5-
import io.reactivex.Single
6+
import kotlinx.coroutines.flow.Flow
67

78
interface MediaRepository {
8-
fun fetchFolders(): Single<ArrayList<Folder>>
9-
fun fetchDocs(): Single<ArrayList<MiMedia>>
9+
suspend fun fetchFolders(): Flow<Result<ArrayList<Folder>>>
10+
suspend fun fetchDocs(): Flow<Result<ArrayList<MiMedia>>>
1011
}

lassi/src/main/java/com/lassi/presentation/camera/CameraFragment.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ class CameraFragment : LassiBaseViewModelFragment<CameraViewModel>(), View.OnCli
224224
} else {
225225
R.string.camera_storage_permission_rational
226226
}
227-
val alertDialog = AlertDialog.Builder(requireContext())
227+
val alertDialog = AlertDialog.Builder(requireContext(), R.style.dialogTheme)
228228
.setMessage(alertMessage)
229229
.setCancelable(false)
230230
.setPositiveButton(R.string.ok) { _, _ ->

0 commit comments

Comments
 (0)