Skip to content

Commit 85c35a2

Browse files
Basic file upload implemented
Implements #32: Basic file upload implemented
2 parents fdf92cf + fe7ddd9 commit 85c35a2

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)