Skip to content

Commit fe7ddd9

Browse files
Basic file upload implemented
added notification channel and support file upload events finalised, and code optimised Ktlintformat applied App crash fixed due to DI
1 parent fdf92cf commit fe7ddd9

27 files changed

+648
-65
lines changed

app/build.gradle

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ dependencies {
5454
implementation "androidx.room:room-runtime:$versions.room"
5555
kapt "androidx.room:room-compiler:$versions.room"
5656

57+
implementation "androidx.work:work-runtime-ktx:$versions.work"
58+
5759
// optional - Kotlin Extensions and Coroutines support for Room
5860
implementation "androidx.room:room-ktx:$versions.room"
5961

@@ -65,6 +67,9 @@ dependencies {
6567
implementation "com.google.dagger:hilt-android:$versions.hilt"
6668
kapt "com.google.dagger:hilt-compiler:$versions.hilt"
6769

70+
//implementation 'androidx.hilt:hilt-work:1.0.0'
71+
//kapt 'androidx.hilt:hilt-compiler:1.0.0'
72+
6873
// Amplify core dependency
6974
implementation "com.amplifyframework:core-kotlin:$versions.amplify_core_kotlin"
7075
implementation "com.amplifyframework:aws-auth-cognito:$versions.amplify_core"
@@ -88,4 +93,9 @@ dependencies {
8893
implementation "com.facebook.shimmer:shimmer:$versions.shimmer"
8994

9095
implementation "com.github.takusemba:spotlight:$versions.spotlight"
96+
97+
implementation 'com.github.dhaval2404:imagepicker:1.8'
98+
99+
implementation 'com.github.florent37:inline-activity-result-kotlin:1.0.4'
100+
implementation 'androidx.documentfile:documentfile:1.0.1'
91101
}

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
android:theme="@style/Theme.VTransfer">
2020
<meta-data android:name="CLOUDINARY_URL" android:value="cloudinary://@code-gambit"/>
2121
<activity
22-
android:name=".ui.MainActivity"
22+
android:name=".ui.activity.main.MainActivity"
2323
android:screenOrientation="portrait">
2424
<intent-filter>
2525
<action android:name="android.intent.action.MAIN" />

app/src/main/java/com/github/code/gambit/data/entity/chache/FileCacheEntity.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ class FileCacheEntity(
1414
@ColumnInfo(name = "name")
1515
var name: String,
1616

17+
@ColumnInfo(name = "hash")
18+
var hash: String,
19+
1720
@ColumnInfo(name = "type")
1821
var type: String,
1922

app/src/main/java/com/github/code/gambit/data/entity/network/FileNetworkEntity.kt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,17 @@ import com.google.gson.annotations.SerializedName
66
class FileNetworkEntity(
77

88
@SerializedName("PK")
9+
@Expose
910
var pk: String,
1011

1112
@SerializedName("SK")
1213
@Expose
1314
var sk: String,
1415

16+
@SerializedName("hash")
17+
@Expose
18+
var hash: String,
19+
1520
@SerializedName("LS1_SK")
1621
@Expose
1722
var ls1_sk: String,
@@ -20,8 +25,19 @@ class FileNetworkEntity(
2025
@Expose
2126
var size: Int,
2227

23-
@SerializedName("type")
28+
@SerializedName("f_type")
2429
@Expose
2530
var type: String
2631

27-
)
32+
) {
33+
companion object {
34+
fun fromString(str: String): FileNetworkEntity {
35+
val arr = str.split('\n')
36+
return FileNetworkEntity(arr[0], arr[1], arr[2], arr[3], arr[4].toInt(), arr[5])
37+
}
38+
}
39+
40+
override fun toString(): String {
41+
return "$pk\n$sk\n$hash\n$ls1_sk\n$size\n$type"
42+
}
43+
}

app/src/main/java/com/github/code/gambit/data/mapper/cache/FileCacheMapper.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ constructor() : EntityMapper<FileCacheEntity, File> {
1313
return File(
1414
id = entity.id,
1515
name = entity.name,
16+
hash = entity.hash,
1617
type = entity.type,
1718
timestamp = entity.timestamp,
1819
size = entity.size,
@@ -24,6 +25,7 @@ constructor() : EntityMapper<FileCacheEntity, File> {
2425
return FileCacheEntity(
2526
id = domainModel.id,
2627
name = domainModel.name,
28+
hash = domainModel.hash,
2729
type = domainModel.type,
2830
timestamp = domainModel.timestamp,
2931
size = domainModel.size,

app/src/main/java/com/github/code/gambit/data/mapper/network/FileNetworkMapper.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ constructor() : EntityMapper<FileNetworkEntity, File> {
1515
return File(
1616
id = "${entity.pk}__${entity.sk}".toBase64(),
1717
name = entity.ls1_sk,
18+
hash = entity.hash,
1819
type = entity.type,
1920
timestamp = entity.sk.split("#")[1],
2021
size = "${entity.size} Mb",
@@ -26,6 +27,7 @@ constructor() : EntityMapper<FileNetworkEntity, File> {
2627
return FileNetworkEntity(
2728
pk = domainModel.id.fromBase64().split("__")[0],
2829
sk = "FILE#${domainModel.timestamp}",
30+
hash = domainModel.hash,
2931
ls1_sk = domainModel.name,
3032
size = domainModel.size.split(" ")[0].toInt(),
3133
type = domainModel.type

app/src/main/java/com/github/code/gambit/data/model/File.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.github.code.gambit.data.model
33
data class File(
44
var id: String,
55
var name: String,
6+
var hash: String,
67
var type: String,
78
var timestamp: String,
89
var size: String,

app/src/main/java/com/github/code/gambit/di/NetworkModule.kt

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ object NetworkModule {
3030

3131
@Singleton
3232
@Provides
33-
fun provideRetroFitBuilder(gson: Gson): Retrofit.Builder {
34-
return Retrofit.Builder().baseUrl("https://open-api.xyz/placeholder/")
33+
fun provideRetroFitBuilder(gson: Gson, @Named(AppConstant.Named.BASE_URL) baseUrl: String): Retrofit.Builder {
34+
return Retrofit.Builder().baseUrl(baseUrl)
3535
.addConverterFactory(GsonConverterFactory.create(gson))
3636
}
3737

@@ -41,13 +41,6 @@ object NetworkModule {
4141
return retrofitBuilder.build().create(ApiService::class.java)
4242
}
4343

44-
@Singleton
45-
@Named(AppConstant.Named.USER_ID)
46-
@Provides
47-
fun provideUserId(preferenceManager: PreferenceManager): String {
48-
return preferenceManager.getUserId()!!
49-
}
50-
5144
@Singleton
5245
@Provides
5346
fun provideFileService(apiService: ApiService): FileService {
@@ -62,7 +55,15 @@ object NetworkModule {
6255

6356
@Singleton
6457
@Provides
65-
fun provideUserService(apiService: ApiService, @Named("UID") userId: String): UserService {
58+
fun provideUserService(apiService: ApiService, preferenceManager: PreferenceManager): UserService {
59+
val userId = preferenceManager.getUserId()!!
6660
return UserServiceImpl(apiService, userId)
6761
}
62+
63+
@Singleton
64+
@Named(AppConstant.Named.BASE_URL)
65+
@Provides
66+
fun providesBaseUrl(): String {
67+
return "https://mhv71te0rh.execute-api.ap-south-1.amazonaws.com/beta/"
68+
}
6869
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.github.code.gambit.helper.file
2+
3+
import com.github.code.gambit.data.entity.network.FileNetworkEntity
4+
5+
sealed class FileUploadState {
6+
data class UploadStarted(val fileName: String) : FileUploadState()
7+
data class UploadSuccess(val file: FileNetworkEntity) : FileUploadState()
8+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package com.github.code.gambit.network
2+
3+
import android.app.NotificationChannel
4+
import android.app.NotificationManager
5+
import android.app.PendingIntent
6+
import android.content.Context
7+
import android.content.Intent
8+
import android.os.Build
9+
import androidx.core.app.NotificationCompat
10+
import androidx.core.app.NotificationManagerCompat
11+
import androidx.work.CoroutineWorker
12+
import androidx.work.WorkerParameters
13+
import androidx.work.workDataOf
14+
import com.github.code.gambit.R
15+
import com.github.code.gambit.data.entity.network.FileNetworkEntity
16+
import com.github.code.gambit.network.api.ApiService
17+
import com.github.code.gambit.network.api.file.FileService
18+
import com.github.code.gambit.network.api.file.FileServiceImpl
19+
import com.github.code.gambit.ui.activity.main.MainActivity
20+
import com.github.code.gambit.utility.AppConstant
21+
import com.google.gson.GsonBuilder
22+
import io.ipfs.kotlin.defaults.InfuraIPFS
23+
import retrofit2.Retrofit
24+
import retrofit2.converter.gson.GsonConverterFactory
25+
import timber.log.Timber
26+
import java.io.File
27+
28+
class FileUploadWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx, params) {
29+
30+
/**
31+
* @inputData filePath: String is the absolute file path
32+
* @inputData fileName: String name of the file
33+
* @inputData userId: String Id of the user used for api call
34+
* @inputData fileSize: Int size of the file in Mb
35+
*
36+
* @outputData data: Data toString of FileNetworkEntitiy
37+
*/
38+
override suspend fun doWork(): Result {
39+
val filePath: String = inputData.getString(AppConstant.Worker.FILE_URI_KEY)!!
40+
val fileName: String = inputData.getString(AppConstant.Worker.FILE_NAME_KEY)!!
41+
val userId: String = inputData.getString(AppConstant.Worker.USER_ID)!!
42+
val fileSize: Int = inputData.getInt(AppConstant.Worker.FILE_SIZE_KEY, -1)
43+
makeStatusNotification(1, "New file", "Uploading file $fileName of size $fileSize mb", true)
44+
val file = File(filePath)
45+
val res = InfuraIPFS().add.file(file, fileName, fileName).Hash
46+
// val res = "test-hash-to-avoid-unnecessary-server-call"
47+
Timber.tag("out").i(res)
48+
val fileService = getFileService()
49+
val task = fileService.uploadFile(userId, FileNetworkEntity("", "", res, fileName, fileSize, fileName.split(".")[1]))
50+
val data = workDataOf(AppConstant.Worker.FILE_OUTPUT_KEY to task.toString())
51+
makeStatusNotification(1, "File Uploaded", task.toString(), false)
52+
return Result.success(data)
53+
}
54+
55+
private fun getApiService(): ApiService {
56+
return Retrofit.Builder().baseUrl(AppConstant.BASE_URL)
57+
.addConverterFactory(
58+
GsonConverterFactory
59+
.create(
60+
GsonBuilder()
61+
.excludeFieldsWithoutExposeAnnotation().create()
62+
)
63+
).build().create(ApiService::class.java)
64+
}
65+
66+
private fun getFileService(): FileService {
67+
return FileServiceImpl(getApiService())
68+
}
69+
70+
/**
71+
* @param id Notification id
72+
* @param title notification title
73+
* @param message Notification message
74+
* @param progress determines whether to show progress or not
75+
*/
76+
private fun makeStatusNotification(id: Int, title: String, message: String, progress: Boolean) {
77+
val context = applicationContext
78+
// Make a channel if necessary
79+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
80+
// Create the NotificationChannel, but only on API 26+ because
81+
// the NotificationChannel class is new and not in the support library
82+
val name = AppConstant.Notification.CHANNEL_NAME
83+
val description = AppConstant.Notification.CHANNEL_DESCRIPTION
84+
val importance = NotificationManager.IMPORTANCE_HIGH
85+
val channel = NotificationChannel(AppConstant.Notification.CHANNEL_ID, name, importance)
86+
channel.description = description
87+
88+
// Add the channel
89+
val notificationManager =
90+
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?
91+
92+
notificationManager?.createNotificationChannel(channel)
93+
}
94+
95+
val intent = Intent(context, MainActivity::class.java).apply {
96+
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
97+
}
98+
99+
val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
100+
101+
// Create the notification
102+
val builder = NotificationCompat.Builder(context, AppConstant.Notification.CHANNEL_ID)
103+
.setSmallIcon(R.drawable.ic_launcher_foreground)
104+
.setContentTitle(title)
105+
.setContentText(message)
106+
.setContentIntent(pendingIntent)
107+
.setPriority(NotificationCompat.PRIORITY_HIGH)
108+
.setStyle(NotificationCompat.BigTextStyle().bigText(message))
109+
.setVibrate(LongArray(0))
110+
111+
if (progress) {
112+
builder.setProgress(0, 0, true)
113+
}
114+
115+
// Show the notification
116+
NotificationManagerCompat.from(context).notify(id, builder.build())
117+
}
118+
}

0 commit comments

Comments
 (0)