Skip to content

Commit bb7806f

Browse files
committed
2 parents a563857 + b081c20 commit bb7806f

22 files changed

+999
-192
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
<img src="images/image1.png" alt="Screenshot 1" width="200"/>
2828
<img src="images/image2.png" alt="Screenshot 2" width="200"/>
2929
<img src="images/image3.png" alt="Screenshot 3" width="200"/>
30+
<img src="images/image4.png" alt="Screenshot 3" width="200"/>
3031
</p>
3132

3233
---
@@ -139,7 +140,7 @@ Whether it's bug fixes, new features, or improvements, we appreciate your contri
139140
---
140141
## Contributors
141142

142-
![Contributors](https://contributors-img.web.app/image?repo=CodeWithTamim/ConvertIt)
143+
![Contributors](https://contributors-img.web.app/image?repo=TheByteArray/ConvertIt)
143144

144145
---
145146

app/libs/taglib.aar

1.48 MB
Binary file not shown.

app/src/main/AndroidManifest.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
88
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
99
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
10-
<uses-sdk tools:overrideLibrary="com.arthenica.ffmpegkit" android:minSdkVersion="21" />
10+
<uses-sdk
11+
android:minSdkVersion="21"
12+
tools:overrideLibrary="com.kyant.taglib,com.arthenica.ffmpegkit" />
13+
1114

1215
<application
1316
android:name=".App"

app/src/main/java/com/nasahacker/convertit/App.kt

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,18 @@ class App : Application() {
3838

3939
private fun initChannel() {
4040
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
41-
NotificationManagerCompat.from(this).createNotificationChannel(
42-
NotificationChannel(
43-
CHANNEL_ID,
44-
CHANNEL_NAME,
45-
NotificationManager.IMPORTANCE_DEFAULT,
46-
),
47-
)
41+
val channel = NotificationChannel(
42+
CHANNEL_ID,
43+
CHANNEL_NAME,
44+
NotificationManager.IMPORTANCE_LOW,
45+
).apply {
46+
description = "Notifications for audio conversion progress and completion"
47+
setShowBadge(false)
48+
enableLights(false)
49+
enableVibration(false)
50+
setSound(null, null)
51+
}
52+
NotificationManagerCompat.from(this).createNotificationChannel(channel)
4853
}
4954
}
5055

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.nasahacker.convertit.dto
2+
3+
import com.kyant.taglib.Picture
4+
5+
/**
6+
* @author Tamim Hossain
7+
8+
* @license Apache-2.0
9+
*
10+
* ConvertIt is a free and easy-to-use audio converter app.
11+
* It supports popular audio formats like MP3 and M4A.
12+
* With options for high-quality bitrates ranging from 128k to 320k,
13+
* ConvertIt offers a seamless conversion experience tailored to your needs.
14+
*/
15+
16+
data class Metadata(
17+
val title: String = "",
18+
val artist: String = "",
19+
val album: String = "",
20+
val albumArtist: String = "",
21+
val genre: String = "",
22+
val year: String = "",
23+
val track: String = "",
24+
val comment: String = "",
25+
val pictures: List<Picture> = emptyList(),
26+
val propertyMap: Map<String, Array<String>> = emptyMap()
27+
) {
28+
fun toPropertyMap(): Map<String, Array<String>> {
29+
val map = mutableMapOf<String, Array<String>>()
30+
31+
if (title.isNotBlank()) map["TITLE"] = arrayOf(title)
32+
if (artist.isNotBlank()) map["ARTIST"] = arrayOf(artist)
33+
if (album.isNotBlank()) map["ALBUM"] = arrayOf(album)
34+
if (albumArtist.isNotBlank()) map["ALBUMARTIST"] = arrayOf(albumArtist)
35+
if (genre.isNotBlank()) map["GENRE"] = arrayOf(genre)
36+
if (year.isNotBlank()) map["DATE"] = arrayOf(year)
37+
if (track.isNotBlank()) map["TRACKNUMBER"] = arrayOf(track)
38+
if (comment.isNotBlank()) map["COMMENT"] = arrayOf(comment)
39+
40+
return map
41+
}
42+
43+
companion object {
44+
fun fromPropertyMap(propertyMap: Map<String, Array<String>>, pictures: List<Picture> = emptyList()): Metadata {
45+
return Metadata(
46+
title = propertyMap["TITLE"]?.firstOrNull() ?: "",
47+
artist = propertyMap["ARTIST"]?.firstOrNull() ?: "",
48+
album = propertyMap["ALBUM"]?.firstOrNull() ?: "",
49+
albumArtist = propertyMap["ALBUMARTIST"]?.firstOrNull() ?: "",
50+
genre = propertyMap["GENRE"]?.firstOrNull() ?: "",
51+
year = propertyMap["DATE"]?.firstOrNull() ?: propertyMap["YEAR"]?.firstOrNull() ?: "",
52+
track = propertyMap["TRACKNUMBER"]?.firstOrNull() ?: "",
53+
comment = propertyMap["COMMENT"]?.firstOrNull() ?: "",
54+
pictures = pictures,
55+
propertyMap = propertyMap
56+
)
57+
}
58+
}
59+
}

app/src/main/java/com/nasahacker/convertit/service/ConvertItService.kt

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ import com.nasahacker.convertit.util.AppConfig.IS_SUCCESS
4141
import com.nasahacker.convertit.util.AppConfig.URI_LIST
4242
import kotlinx.coroutines.CoroutineScope
4343
import kotlinx.coroutines.Dispatchers
44+
import kotlinx.coroutines.Job
4445
import kotlinx.coroutines.launch
46+
import com.arthenica.ffmpegkit.FFmpegKit
4547

4648
class ConvertItService : Service() {
4749
companion object {
@@ -50,9 +52,23 @@ class ConvertItService : Service() {
5052
}
5153

5254
private val notificationId = 1
55+
private var conversionJob: Job? = null
5356

5457
override fun onBind(intent: Intent?): IBinder? = null
5558

59+
override fun onDestroy() {
60+
super.onDestroy()
61+
Log.i(TAG, "Service destroyed")
62+
63+
// Cancel ongoing conversion job
64+
conversionJob?.cancel()
65+
conversionJob = null
66+
67+
// Cancel all FFmpeg sessions
68+
FFmpegKit.cancel()
69+
Log.i(TAG, "Cancelled all FFmpeg sessions in onDestroy")
70+
}
71+
5672
override fun onCreate() {
5773
super.onCreate()
5874
Log.i(TAG, "Service created - Process ID: ${android.os.Process.myPid()}")
@@ -70,7 +86,16 @@ class ConvertItService : Service() {
7086

7187
if (intent?.action == ACTION_STOP_SERVICE) {
7288
Log.i(TAG, "Stopping service as per user request. startId: $startId")
73-
showCompletionNotification(false)
89+
90+
// Cancel ongoing conversion job
91+
conversionJob?.cancel()
92+
conversionJob = null
93+
94+
// Cancel all FFmpeg sessions
95+
FFmpegKit.cancel()
96+
Log.i(TAG, "Cancelled all FFmpeg sessions")
97+
98+
showCompletionNotification(success = false, cancelled = true)
7499
broadcastConversionResult(Intent().apply { action = CONVERT_BROADCAST_ACTION }, false)
75100
stopForegroundService()
76101
return START_NOT_STICKY
@@ -105,7 +130,7 @@ class ConvertItService : Service() {
105130
return START_NOT_STICKY
106131
}
107132

108-
CoroutineScope(Dispatchers.IO).launch {
133+
conversionJob = CoroutineScope(Dispatchers.IO).launch {
109134
try {
110135
Log.i(TAG, "Starting audio conversion for ${uriList.size} files. startId: $startId")
111136
AppUtil.convertAudio(
@@ -210,22 +235,30 @@ class ConvertItService : Service() {
210235
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
211236
)
212237

213-
val progressText = if (isIndeterminate) {
214-
getString(R.string.label_converting_audio)
238+
val (title, contentText) = if (isIndeterminate) {
239+
getString(R.string.converting_audio_files) to getString(R.string.label_converting_audio)
215240
} else {
216-
"Conversion in progress: $progress%"
241+
// Put percentage in title for better visibility on Android 15+
242+
"${getString(R.string.converting_audio_files)} ($progress%)" to getString(R.string.label_conversion_progress, progress)
217243
}
218244

219245
Log.d(
220-
TAG, "Creating progress notification: $progressText (Indeterminate: $isIndeterminate)"
246+
TAG, "Creating progress notification: $title - $contentText (Indeterminate: $isIndeterminate)"
221247
)
222248

223249
return NotificationCompat.Builder(this, CHANNEL_ID)
224-
.setContentTitle(getString(R.string.converting_audio_files))
225-
.setContentText(progressText).setSmallIcon(R.mipmap.ic_launcher_foreground)
226-
.setProgress(100, progress, isIndeterminate).setAutoCancel(false).setOngoing(true)
227-
.setDefaults(0).setOnlyAlertOnce(true)
228-
.addAction(R.drawable.baseline_stop_24, "Stop", stopPendingIntent).build()
250+
.setContentTitle(title)
251+
.setContentText(contentText)
252+
.setSmallIcon(R.mipmap.ic_launcher_foreground)
253+
.setProgress(100, progress, isIndeterminate)
254+
.setAutoCancel(false)
255+
.setOngoing(true)
256+
.setDefaults(0)
257+
.setOnlyAlertOnce(true)
258+
.setPriority(NotificationCompat.PRIORITY_LOW)
259+
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
260+
.addAction(R.drawable.baseline_stop_24, getString(R.string.label_stop), stopPendingIntent)
261+
.build()
229262
}
230263

231264
private fun updateNotification(progress: Int) {
@@ -244,13 +277,13 @@ class ConvertItService : Service() {
244277
Log.v(TAG, "Updated notification: Progress $progress%")
245278
}
246279

247-
private fun showCompletionNotification(success: Boolean) {
280+
private fun showCompletionNotification(success: Boolean, cancelled: Boolean = false) {
248281
stopForegroundService()
249282

250-
val notificationText = if (success) {
251-
getString(R.string.conversion_success)
252-
} else {
253-
getString(R.string.conversion_failed)
283+
val notificationText = when {
284+
cancelled -> getString(R.string.conversion_cancelled)
285+
success -> getString(R.string.conversion_success)
286+
else -> getString(R.string.conversion_failed)
254287
}
255288

256289
Log.i(TAG, "Showing completion notification: $notificationText")

app/src/main/java/com/nasahacker/convertit/ui/component/DialogConvert.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ fun DialogConvertAlertDialog(
5151
Icon(
5252
imageVector = Icons.Default.Settings,
5353
contentDescription = null,
54-
tint = MaterialTheme.colorScheme.primary,
55-
modifier = Modifier.size(28.dp)
54+
tint = MaterialTheme.colorScheme.primary
5655
)
5756
},
5857
title = {

0 commit comments

Comments
 (0)