diff --git a/app/build.gradle b/app/build.gradle
deleted file mode 100644
index 00c64ca..0000000
--- a/app/build.gradle
+++ /dev/null
@@ -1,77 +0,0 @@
-plugins {
- id 'com.android.application'
- id 'org.jetbrains.kotlin.android'
- id 'androidx.navigation.safeargs.kotlin'
- id 'kotlin-kapt'
-}
-
-android {
- compileSdk 33
-
- defaultConfig {
- applicationId "com.roozbehzarei.filester"
- minSdk 21
- targetSdk 33
- versionCode 3
- versionName "2.0.1"
-
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- }
-
- buildFeatures {
- viewBinding true
- }
-
- buildscript {
- repositories {
- google()
- mavenCentral()
- }
-
- 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'
- }
- }
- namespace 'com.roozbehzarei.filester'
-}
-
-dependencies {
- implementation 'androidx.core:core-ktx:1.9.0'
- implementation 'androidx.appcompat:appcompat:1.6.0'
- implementation 'com.google.android.material:material:1.8.0'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
- // Fragments
- implementation "androidx.fragment:fragment-ktx:$fragment_version"
- // Navigation Component
- implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
- implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
- // ViewModel
- implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
- implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
- // Retrofit with Scalars Converter
- implementation "com.squareup.retrofit2:converter-scalars:$retrofit_version"
- // WorkManager
- implementation "androidx.work:work-runtime-ktx:$work_version"
- // Room
- implementation "androidx.room:room-runtime:$room_version"
- implementation "androidx.room:room-ktx:$room_version"
- kapt "androidx.room:room-compiler:$room_version"
- // CoordinatorLayout
- implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
- // Activity
- implementation "androidx.activity:activity-ktx:$activity_version"
- // SplashScreen
- implementation 'androidx.core:core-splashscreen:1.0.0'
- // Coordinatorlayout
- implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
-}
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
new file mode 100644
index 0000000..1945349
--- /dev/null
+++ b/app/build.gradle.kts
@@ -0,0 +1,88 @@
+plugins {
+ id("com.android.application")
+ id("org.jetbrains.kotlin.android")
+ id("androidx.navigation.safeargs.kotlin")
+ id("com.google.devtools.ksp")
+ id("com.google.gms.google-services")
+ id("com.google.firebase.crashlytics")
+ id("com.google.firebase.firebase-perf")
+}
+
+android {
+ namespace = "com.roozbehzarei.filester"
+ compileSdk = 33
+
+ defaultConfig {
+ applicationId = "com.roozbehzarei.filester"
+ minSdk = 21
+ targetSdk = 33
+ versionCode = 4
+ versionName = "2.1.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildFeatures {
+ viewBinding = true
+ }
+
+ buildTypes {
+ getByName("release") {
+ isMinifyEnabled = 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"
+ }
+ androidResources {
+ generateLocaleConfig = true
+ }
+}
+
+dependencies {
+ val navVersion = "2.5.3"
+ val activityVersion = "1.7.2"
+ val fragmentVersion = "1.6.1"
+ val lifecycleVersion = "2.6.1"
+ val retrofitVersion = "2.9.0"
+ val workVersion = "2.8.1"
+ val roomVersion = "2.5.2"
+
+ implementation("androidx.core:core-ktx:1.10.1")
+ implementation("androidx.appcompat:appcompat:1.6.1")
+ implementation("com.google.android.material:material:1.9.0")
+ implementation("androidx.constraintlayout:constraintlayout:2.1.4")
+ // Fragment
+ implementation("androidx.fragment:fragment-ktx:$fragmentVersion")
+ // Navigation
+ implementation("androidx.navigation:navigation-fragment-ktx:$navVersion")
+ implementation("androidx.navigation:navigation-ui-ktx:$navVersion")
+ // ViewModel
+ implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion")
+ implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion")
+ // Retrofit with Scalars Converter
+ implementation("com.squareup.retrofit2:converter-scalars:$retrofitVersion")
+ // WorkManager
+ implementation("androidx.work:work-runtime-ktx:$workVersion")
+ // Room
+ implementation("androidx.room:room-runtime:$roomVersion")
+ annotationProcessor("androidx.room:room-compiler:$roomVersion")
+ implementation("androidx.room:room-ktx:$roomVersion")
+ ksp("androidx.room:room-compiler:$roomVersion")
+ // Activity
+ implementation("androidx.activity:activity-ktx:$activityVersion")
+ // SplashScreen
+ implementation("androidx.core:core-splashscreen:1.0.1")
+ // Firebase
+ implementation(platform("com.google.firebase:firebase-bom:32.2.0"))
+ implementation("com.google.firebase:firebase-analytics-ktx")
+ implementation("com.google.firebase:firebase-crashlytics-ktx")
+ implementation("com.google.firebase:firebase-perf-ktx")
+}
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 481bb43..ff59496 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -1,6 +1,6 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
+# proguardFiles setting in build.gradle.kts.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json
index e24f270..1dee2e6 100644
--- a/app/release/output-metadata.json
+++ b/app/release/output-metadata.json
@@ -11,8 +11,8 @@
"type": "SINGLE",
"filters": [],
"attributes": [],
- "versionCode": 3,
- "versionName": "2.0.1",
+ "versionCode": 4,
+ "versionName": "2.1.0",
"outputFile": "app-release.apk"
}
],
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e27666e..966af37 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,9 +1,8 @@
+ xmlns:tools="http://schemas.android.com/tools">
-
+
+
+
+
+
-
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/roozbehzarei/filester/NotificationUtils.kt b/app/src/main/java/com/roozbehzarei/filester/NotificationUtils.kt
deleted file mode 100644
index 2119cd9..0000000
--- a/app/src/main/java/com/roozbehzarei/filester/NotificationUtils.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.roozbehzarei.filester
-
-import android.content.Context
-import androidx.core.app.NotificationCompat
-import androidx.core.app.NotificationManagerCompat
-
-
-const val CHANNEL_ID = "FILESTER"
-
-fun showNotification(
- context: Context,
- notificationId: Int,
- title: String,
- description: String,
- showProgress: Boolean
-) {
- val notification = NotificationCompat.Builder(context, CHANNEL_ID)
- .setSmallIcon(R.drawable.ic_upload)
- .setContentTitle(title)
- .setContentText(description)
- .setPriority(NotificationCompat.PRIORITY_DEFAULT)
- .setAutoCancel(true)
- if (showProgress) {
- notification.setProgress(0, 0, true)
- }
- with(NotificationManagerCompat.from(context)) {
- notify(notificationId, notification.build())
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/roozbehzarei/filester/ui/AboutFragment.kt b/app/src/main/java/com/roozbehzarei/filester/ui/AboutFragment.kt
index 8bb512d..39fb149 100644
--- a/app/src/main/java/com/roozbehzarei/filester/ui/AboutFragment.kt
+++ b/app/src/main/java/com/roozbehzarei/filester/ui/AboutFragment.kt
@@ -11,7 +11,7 @@ import com.roozbehzarei.filester.BuildConfig
import com.roozbehzarei.filester.R
import com.roozbehzarei.filester.databinding.FragmentAboutBinding
-private const val GITHUB_URL = "https://github.com/roozbehzarei"
+private const val GITHUB_URL = "https://roozbehzarei.me/project/filester/"
private const val DONATE_URL = "https://www.buymeacoffee.com/roozbehzarei/"
private const val TRANSFER_URL = "https://transfer.sh/"
@@ -46,16 +46,6 @@ class AboutFragment : Fragment() {
}
}
- override fun onResume() {
- super.onResume()
- requireActivity().actionBar?.setDisplayShowTitleEnabled(false)
- }
-
- override fun onPause() {
- super.onPause()
- requireActivity().actionBar?.setDisplayShowTitleEnabled(true)
- }
-
/**
* Open the passed [url] in browser
*/
diff --git a/app/src/main/java/com/roozbehzarei/filester/ui/MainActivity.kt b/app/src/main/java/com/roozbehzarei/filester/ui/MainActivity.kt
index 56bdc3c..237ed85 100644
--- a/app/src/main/java/com/roozbehzarei/filester/ui/MainActivity.kt
+++ b/app/src/main/java/com/roozbehzarei/filester/ui/MainActivity.kt
@@ -16,7 +16,6 @@ import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupWithNavController
import com.google.android.material.appbar.AppBarLayout
-import com.roozbehzarei.filester.CHANNEL_ID
import com.roozbehzarei.filester.R
import com.roozbehzarei.filester.databinding.ActivityMainBinding
@@ -54,8 +53,7 @@ class MainActivity : AppCompatActivity() {
}
// Change the color of the navigation bars
- val windowInsetsController =
- WindowCompat.getInsetsController(window, binding.root)
+ val windowInsetsController = WindowCompat.getInsetsController(window, binding.root)
val currentNightMode =
applicationContext.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
when (currentNightMode) {
@@ -63,6 +61,7 @@ class MainActivity : AppCompatActivity() {
windowInsetsController.isAppearanceLightNavigationBars = true
windowInsetsController.isAppearanceLightStatusBars = true
}
+
Configuration.UI_MODE_NIGHT_YES -> {
windowInsetsController.isAppearanceLightNavigationBars = false
windowInsetsController.isAppearanceLightStatusBars = false
@@ -89,8 +88,10 @@ class MainActivity : AppCompatActivity() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = getString(R.string.channel_name)
val descriptionText = getString(R.string.channel_description)
- val importance = NotificationManager.IMPORTANCE_DEFAULT
- val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
+ val importance = NotificationManager.IMPORTANCE_LOW
+ val channel = NotificationChannel(
+ getString(R.string.notification_channel_id), name, importance
+ ).apply {
description = descriptionText
}
// Register the channel with the system
diff --git a/app/src/main/java/com/roozbehzarei/filester/ui/MainFragment.kt b/app/src/main/java/com/roozbehzarei/filester/ui/MainFragment.kt
index f333c48..4ba19a0 100644
--- a/app/src/main/java/com/roozbehzarei/filester/ui/MainFragment.kt
+++ b/app/src/main/java/com/roozbehzarei/filester/ui/MainFragment.kt
@@ -1,13 +1,23 @@
package com.roozbehzarei.filester.ui
+import android.Manifest
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
+import android.content.pm.PackageManager
import android.net.Uri
+import android.os.Build
import android.os.Bundle
-import android.view.*
-import android.widget.Toast
+import android.view.LayoutInflater
+import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
+import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
+import androidx.annotation.RequiresApi
+import androidx.core.content.ContextCompat
import androidx.core.view.MenuHost
import androidx.core.view.MenuProvider
import androidx.documentfile.provider.DocumentFile
@@ -32,6 +42,8 @@ class MainFragment : Fragment() {
// Binding object instance with access to the views in the fragment_upload.xml layout
private lateinit var binding: FragmentMainBinding
+ private lateinit var requestPermissionLauncher: ActivityResultLauncher
+
private val viewModel: FilesterViewModel by activityViewModels {
FilesterViewModelFactory(
(activity?.application as BaseApplication).database.fileDao(),
@@ -47,10 +59,16 @@ class MainFragment : Fragment() {
}
}
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ requestPermissionLauncher =
+ registerForActivityResult(ActivityResultContracts.RequestPermission()) { _ ->
+ fileSelector.launch("*/*")
+ }
+ }
+
override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
// Inflate the layout XML file and return a binding object instance
binding = FragmentMainBinding.inflate(inflater, container, false)
@@ -74,10 +92,8 @@ class MainFragment : Fragment() {
activity?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip: ClipData = ClipData.newPlainText("file url", file.fileUrl)
clipboard.setPrimaryClip(clip)
- Toast.makeText(
- context,
- getString(R.string.toast_clipboard),
- Toast.LENGTH_SHORT
+ Snackbar.make(
+ binding.snackbarLayout, getString(R.string.snackbar_clipboard), Snackbar.LENGTH_SHORT
).show()
}
binding.fileListView.adapter = adapter
@@ -100,7 +116,11 @@ class MainFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.fab.setOnClickListener {
- fileSelector.launch("*/*")
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ checkNotificationPermission()
+ } else {
+ fileSelector.launch("*/*")
+ }
}
viewModel.outputWorkInfo.observe(viewLifecycleOwner, workInfoObserver())
}
@@ -108,7 +128,7 @@ class MainFragment : Fragment() {
private fun workInfoObserver(): Observer> {
return Observer {
// If there are no matching work info, do nothing
- if (it.isNullOrEmpty()) {
+ if (it.isEmpty()) {
return@Observer
}
val workInfo = it[0]
@@ -116,11 +136,10 @@ class MainFragment : Fragment() {
if (!workInfo.state.isFinished) {
isUploadInProgress(true)
Snackbar.make(
- binding.root,
+ binding.snackbarLayout,
resources.getString(R.string.snackbar_uploading),
Snackbar.LENGTH_LONG
- )
- .show()
+ ).show()
} else if (workInfo.state == WorkInfo.State.SUCCEEDED) {
showDialog(true, fileUrl)
viewModel.clearWorkQueue()
@@ -145,10 +164,10 @@ class MainFragment : Fragment() {
activity?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip: ClipData = ClipData.newPlainText("file url", fileUrl)
clipboard.setPrimaryClip(clip)
- Toast.makeText(
- context,
- getString(R.string.toast_clipboard),
- Toast.LENGTH_SHORT
+ Snackbar.make(
+ binding.snackbarLayout,
+ getString(R.string.snackbar_clipboard),
+ Snackbar.LENGTH_SHORT
).show()
}
.setNegativeButton(resources.getString(R.string.dialog_button_close)) { dialog, _ ->
@@ -160,9 +179,7 @@ class MainFragment : Fragment() {
.setPositiveButton(resources.getString(R.string.dialog_button_close)) { dialog, _ ->
dialog.dismiss()
}
- }
- .setCancelable(false)
- .show()
+ }.setCancelable(false).show()
}
private fun isUploadInProgress(state: Boolean) {
@@ -175,4 +192,19 @@ class MainFragment : Fragment() {
}
}
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private fun checkNotificationPermission() {
+ when {
+ ContextCompat.checkSelfPermission(
+ requireContext(), Manifest.permission.POST_NOTIFICATIONS
+ ) != PackageManager.PERMISSION_GRANTED -> requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
+
+ shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS) -> {
+ // Explain to the user why the app needs this permission
+ // To be implemented in future releases
+ }
+
+ else -> fileSelector.launch("*/*")
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/roozbehzarei/filester/worker/UploadWorker.kt b/app/src/main/java/com/roozbehzarei/filester/worker/UploadWorker.kt
index 27544bb..cb3c9c2 100644
--- a/app/src/main/java/com/roozbehzarei/filester/worker/UploadWorker.kt
+++ b/app/src/main/java/com/roozbehzarei/filester/worker/UploadWorker.kt
@@ -1,14 +1,23 @@
package com.roozbehzarei.filester.worker
+import android.app.Notification
+import android.app.NotificationManager
+import android.app.PendingIntent
import android.content.Context
+import android.content.Intent
+import android.content.pm.ServiceInfo
import android.net.Uri
+import android.os.Build
+import androidx.core.app.NotificationCompat
+import androidx.core.content.ContextCompat
import androidx.work.CoroutineWorker
+import androidx.work.ForegroundInfo
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import com.roozbehzarei.filester.BaseApplication
import com.roozbehzarei.filester.R
import com.roozbehzarei.filester.network.TransferApi
-import com.roozbehzarei.filester.showNotification
+import com.roozbehzarei.filester.ui.MainActivity
import com.roozbehzarei.filester.viewmodel.KEY_FILE_NAME
import com.roozbehzarei.filester.viewmodel.KEY_FILE_URI
import okhttp3.MediaType
@@ -19,23 +28,26 @@ import java.io.File
class UploadWorker(private val context: Context, params: WorkerParameters) :
CoroutineWorker(context, params) {
+ private val notificationManager =
+ context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
private val resolver = context.contentResolver
private val fileDao = BaseApplication().database.fileDao()
override suspend fun doWork(): Result {
- return try {
- showNotification(
- context = applicationContext,
- title = applicationContext.getString(R.string.notification_title_in_progress),
- description = applicationContext.getString(R.string.notification_description_in_progress),
- notificationId = 1,
- showProgress = true
+
+ setForeground(
+ createForegroundInfo(
+ context.getString(R.string.notification_title_start)
)
- val resourceUri = Uri.parse(inputData.getString(KEY_FILE_URI))
- val fileName = inputData.getString(KEY_FILE_NAME)
- val mediaType = MediaType.parse(resolver.getType(resourceUri)!!)
- val inputStream = resolver.openInputStream(resourceUri)
- val file = File(context.cacheDir, fileName!!)
+ )
+
+ val resourceUri = Uri.parse(inputData.getString(KEY_FILE_URI))
+ val fileName = inputData.getString(KEY_FILE_NAME)
+ val mediaType = MediaType.parse(resolver.getType(resourceUri)!!)
+ val inputStream = resolver.openInputStream(resourceUri)
+ val file = File(context.cacheDir, fileName!!)
+
+ return try {
inputStream.use { input ->
file.outputStream().use { output ->
input?.copyTo(output)
@@ -45,9 +57,12 @@ class UploadWorker(private val context: Context, params: WorkerParameters) :
inputStream?.close()
file.length()
val filePart = MultipartBody.Part.createFormData(
- "files",
- file.name,
- RequestBody.create(mediaType, file)
+ "files", file.name, RequestBody.create(mediaType, file)
+ )
+ setForeground(
+ createForegroundInfo(
+ context.getString(R.string.notification_title_in_progress)
+ )
)
val apiResponse = TransferApi.retrofitService.sendFile(filePart)
val responseBody = apiResponse.body()
@@ -59,33 +74,48 @@ class UploadWorker(private val context: Context, params: WorkerParameters) :
fileSize = file.length() / 1024 / 1024
)
fileDao.insert(newFileEntry)
- showNotification(
- context = applicationContext,
- title = applicationContext.getString(R.string.title_upload_success),
- description = applicationContext.getString(R.string.message_upload_success),
- notificationId = 1,
- showProgress = false
+ notificationManager.notify(
+ 1, createNotification(context.getString(R.string.title_upload_success))
)
Result.success(outputData)
} else {
- showNotification(
- context = applicationContext,
- title = applicationContext.getString(R.string.title_upload_error),
- description = applicationContext.getString(R.string.message_upload_error),
- notificationId = 1,
- showProgress = false
+ notificationManager.notify(
+ 1, createNotification(context.getString(R.string.title_upload_error))
)
Result.failure()
}
} catch (e: Exception) {
- showNotification(
- context = applicationContext,
- title = applicationContext.getString(R.string.title_upload_error),
- description = applicationContext.getString(R.string.message_upload_error),
- notificationId = 1,
- showProgress = false
+ notificationManager.notify(
+ 1, createNotification(context.getString(R.string.title_upload_error))
)
Result.failure()
}
}
+
+ private fun createForegroundInfo(progress: String): ForegroundInfo {
+ val notificationChannelId = context.getString(R.string.notification_channel_id)
+ val notification =
+ NotificationCompat.Builder(context, notificationChannelId).setContentTitle(progress)
+ .setSmallIcon(R.drawable.ic_notification)
+ .setColor(ContextCompat.getColor(applicationContext, R.color.seed)).setOngoing(true)
+ .setProgress(0, 0, true).build()
+
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ ForegroundInfo(0, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC)
+ } else {
+ ForegroundInfo(0, notification)
+ }
+ }
+
+ private fun createNotification(progress: String): Notification {
+ val notificationChannelId = context.getString(R.string.notification_channel_id)
+ val intent = Intent(applicationContext, MainActivity::class.java)
+ val pendingIntent = PendingIntent.getActivity(
+ applicationContext, 0, intent, PendingIntent.FLAG_IMMUTABLE
+ )
+ return NotificationCompat.Builder(applicationContext, notificationChannelId)
+ .setContentTitle(progress).setSmallIcon(R.drawable.ic_notification)
+ .setColor(ContextCompat.getColor(applicationContext, R.color.seed)).setAutoCancel(true)
+ .setContentIntent(pendingIntent).build()
+ }
}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_notification.xml b/app/src/main/res/drawable/ic_notification.xml
new file mode 100644
index 0000000..d8c9358
--- /dev/null
+++ b/app/src/main/res/drawable/ic_notification.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml
index 79d981b..d798303 100644
--- a/app/src/main/res/layout/fragment_main.xml
+++ b/app/src/main/res/layout/fragment_main.xml
@@ -49,7 +49,7 @@
android:backgroundTint="@color/seed"
android:contentDescription="@string/fab_label"
android:src="@drawable/ic_upload"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/snackbarLayout"
app:layout_constraintEnd_toEndOf="parent"
app:tint="@android:color/black" />
@@ -65,4 +65,10 @@
app:layout_constraintStart_toStartOf="parent"
app:trackColor="@android:color/transparent" />
+
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml
index 39c5854..c7f7bf1 100644
--- a/app/src/main/res/navigation/nav_graph.xml
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -6,7 +6,7 @@
+ android:label="@string/empty" />
+
+ فایلستر
+ بارگذاری آسان فایل
+ نسخه: %1$s
+ کپیلفت © 2023 توسط روزبه زارعی
+ درباره
+ حمایت مالی
+ وبسایت
+ بارگذاری انجام شد
+ فایل آپلود شده برای 14 روز آینده در دسترس خواهد بود.
+ کپی نشانی
+ بستن
+ بارگذاری انجام نشد
+ خطایی رخ داده است. لطفا دوباره تلاش نمایید.
+ نشانی کپی شد
+ در حال بارگذاری فایل، لطفا صبر نمایید.
+ هنوز فایلی بارگذاری نکردهاید.\nابتدا فایلی را بارگذاری نمایید.
+ اطلاع رسانی درباره وضعیت بارگذاری
+ اطلاع رسانی درباره موفقیت آمیز بودن و یا با خطا مواجه شدن بارگذاری
+ بارگذاری فایل
+ تنظیمات
+ در حال آماده سازی بارگذاری…
+ در حال بارگذاری…
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 5802a51..3820969 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -2,25 +2,26 @@
Filester
Simple File Uploader
Version: %1$s
- Copyleft © 2022 by Roozbeh Zarei
+ Copyleft © 2023 by Roozbeh Zarei
About
transfer.sh
Donate
- GitHub Repo
+ Website
Upload successful
- Your uploaded file will be available on the internet for the next 14 days.
+ Your uploaded file will be available for the next 14 days.
Copy Link
Close
Upload failed
Something went wrong. Please try again.
- Link copied to clipboard
+ Link copied to clipboard
Uploading file, please wait.
- App info
You haven\'t uploaded any files yet.\nTry uploading a file first.
Upload progress status
Notify when upload is in progress, successful or failed.
- Upload in progress
- Please wait
Upload a file
Settings
+
+ filester_notification_id
+ Initializing upload…
+ Uploading…
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index ab5dda5..0000000
--- a/build.gradle
+++ /dev/null
@@ -1,26 +0,0 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-buildscript {
- ext {
- nav_version = "2.5.3"
- fragment_version = "1.5.5"
- lifecycle_version = "2.5.1"
- retrofit_version = "2.9.0"
- work_version = "2.7.1"
- room_version = "2.5.0"
- activity_version = "1.6.1"
- }
- dependencies {
- classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
- }
-}
-
-plugins {
- id 'com.android.application' version '7.4.0' apply false
- id 'com.android.library' version '7.4.0' apply false
- id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
-}
-
-
-task clean(type: Delete) {
- delete rootProject.buildDir
-}
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 0000000..1c6a0c7
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,17 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ dependencies {
+ val navVersion = "2.6.0"
+ classpath("androidx.navigation:navigation-safe-args-gradle-plugin:$navVersion")
+ }
+}
+
+plugins {
+ id("com.android.application") version "8.1.0" apply false
+ id("com.android.library") version "8.1.0" apply false
+ id("org.jetbrains.kotlin.android") version "1.9.0" apply false
+ id("com.google.devtools.ksp") version "1.9.0-1.0.12" apply false
+ id("com.google.gms.google-services") version "4.3.15" apply false
+ id("com.google.firebase.crashlytics") version "2.9.7" apply false
+ id("com.google.firebase.firebase-perf") version "1.4.2" apply false
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index cd0519b..022338b 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -20,4 +20,6 @@ kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
-android.nonTransitiveRClass=true
\ No newline at end of file
+android.nonTransitiveRClass=true
+android.defaults.buildfeatures.buildconfig=true
+android.nonFinalResIds=false
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 45011a2..3211692 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sat Jan 28 05:52:15 PST 2023
+#Thu Jul 27 08:14:26 IRST 2023
distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
distributionPath=wrapper/dists
-zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/settings.gradle b/settings.gradle.kts
similarity index 95%
rename from settings.gradle
rename to settings.gradle.kts
index 88abd25..5835d08 100644
--- a/settings.gradle
+++ b/settings.gradle.kts
@@ -13,4 +13,4 @@ dependencyResolutionManagement {
}
}
rootProject.name = "Filester"
-include ':app'
+include(":app")
\ No newline at end of file