Skip to content

Commit f7a3444

Browse files
chimnayajithchimnayajith
authored andcommitted
lightbox: Add download button to bottom app bar.
Fixes: #42
1 parent 3ac709c commit f7a3444

30 files changed

+658
-2
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Autogenerated from Pigeon (v26.0.2), do not edit directly.
2+
// See also: https://pub.dev/packages/pigeon
3+
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
4+
5+
package com.zulip.flutter
6+
7+
import android.util.Log
8+
import io.flutter.plugin.common.BasicMessageChannel
9+
import io.flutter.plugin.common.BinaryMessenger
10+
import io.flutter.plugin.common.EventChannel
11+
import io.flutter.plugin.common.MessageCodec
12+
import io.flutter.plugin.common.StandardMethodCodec
13+
import io.flutter.plugin.common.StandardMessageCodec
14+
import java.io.ByteArrayOutputStream
15+
import java.nio.ByteBuffer
16+
private object DownloadManagerPigeonUtils {
17+
18+
fun wrapResult(result: Any?): List<Any?> {
19+
return listOf(result)
20+
}
21+
22+
fun wrapError(exception: Throwable): List<Any?> {
23+
return if (exception is DownloadManagerError) {
24+
listOf(
25+
exception.code,
26+
exception.message,
27+
exception.details
28+
)
29+
} else {
30+
listOf(
31+
exception.javaClass.simpleName,
32+
exception.toString(),
33+
"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception)
34+
)
35+
}
36+
}
37+
}
38+
39+
/**
40+
* Error class for passing custom error details to Flutter via a thrown PlatformException.
41+
* @property code The error code.
42+
* @property message The error message.
43+
* @property details The error details. Must be a datatype supported by the api codec.
44+
*/
45+
class DownloadManagerError (
46+
val code: String,
47+
override val message: String? = null,
48+
val details: Any? = null
49+
) : Throwable()
50+
private open class DownloadManagerPigeonCodec : StandardMessageCodec() {
51+
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
52+
return super.readValueOfType(type, buffer)
53+
}
54+
override fun writeValue(stream: ByteArrayOutputStream, value: Any?) {
55+
super.writeValue(stream, value)
56+
}
57+
}
58+
59+
60+
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
61+
interface DownloadManagerHostApi {
62+
/**
63+
* Downloads a file using the given URL and saves it with the specified file name in the Downloads directory.
64+
* Returns a success message or an error message.
65+
*/
66+
fun downloadFile(fileUrl: String, fileName: String, callback: (Result<String>) -> Unit)
67+
68+
companion object {
69+
/** The codec used by DownloadManagerHostApi. */
70+
val codec: MessageCodec<Any?> by lazy {
71+
DownloadManagerPigeonCodec()
72+
}
73+
/** Sets up an instance of `DownloadManagerHostApi` to handle messages through the `binaryMessenger`. */
74+
@JvmOverloads
75+
fun setUp(binaryMessenger: BinaryMessenger, api: DownloadManagerHostApi?, messageChannelSuffix: String = "") {
76+
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
77+
run {
78+
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.zulip.DownloadManagerHostApi.downloadFile$separatedMessageChannelSuffix", codec)
79+
if (api != null) {
80+
channel.setMessageHandler { message, reply ->
81+
val args = message as List<Any?>
82+
val fileUrlArg = args[0] as String
83+
val fileNameArg = args[1] as String
84+
api.downloadFile(fileUrlArg, fileNameArg) { result: Result<String> ->
85+
val error = result.exceptionOrNull()
86+
if (error != null) {
87+
reply.reply(DownloadManagerPigeonUtils.wrapError(error))
88+
} else {
89+
val data = result.getOrNull()
90+
reply.reply(DownloadManagerPigeonUtils.wrapResult(data))
91+
}
92+
}
93+
}
94+
} else {
95+
channel.setMessageHandler(null)
96+
}
97+
}
98+
}
99+
}
100+
}

android/app/src/main/kotlin/com/zulip/flutter/ZulipPlugin.kt

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.zulip.flutter
22

33
import android.annotation.SuppressLint
4+
import android.app.DownloadManager
45
import android.content.ContentUris
56
import android.content.ContentValues
67
import android.content.Context
78
import android.content.Intent
89
import android.media.AudioAttributes
10+
import android.media.MediaScannerConnection
911
import android.net.Uri
1012
import android.os.Build
1113
import android.os.Bundle
@@ -19,6 +21,7 @@ import androidx.core.app.NotificationCompat
1921
import androidx.core.app.NotificationManagerCompat
2022
import androidx.core.graphics.drawable.IconCompat
2123
import io.flutter.embedding.engine.plugins.FlutterPlugin
24+
import org.json.JSONObject
2225
import androidx.core.net.toUri
2326

2427
private const val TAG = "ZulipPlugin"
@@ -284,17 +287,42 @@ private class AndroidNotificationHost(val context: Context)
284287
}
285288
}
286289

290+
/** Host class for handling downloads via DownloadManager */
291+
class DownloadHost(private val context: Context) : DownloadManagerHostApi {
292+
293+
/** Downloads a file from the given URL and saves it to the specified filename in the Downloads folder. */
294+
override fun downloadFile(fileUrl: String, fileName: String, callback: (Result<String>) -> Unit) {
295+
val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
296+
297+
val uri = fileUrl.toUri()
298+
299+
val request = DownloadManager.Request(uri).apply {
300+
setTitle("Downloading $fileName")
301+
setDescription("File is being downloaded...")
302+
setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName)
303+
setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
304+
}
305+
// Queue the download
306+
downloadManager.enqueue(request)
307+
callback(Result.success("Download started successfully for: $fileName"))
308+
}
309+
}
310+
287311
/** A Flutter plugin for the Zulip app's ad-hoc needs. */
288312
// @Keep is needed because this class is used only
289313
// from ZulipShimPlugin, via reflection.
290314
@Keep
291315
class ZulipPlugin : FlutterPlugin { // TODO ActivityAware too?
292316
private var notificationHost: AndroidNotificationHost? = null
317+
private var downloadHost: DownloadHost? = null
293318

294319
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
295320
Log.d(TAG, "Attaching to Flutter engine.")
296321
notificationHost = AndroidNotificationHost(binding.applicationContext)
322+
downloadHost = DownloadHost(binding.applicationContext)
323+
297324
AndroidNotificationHostApi.setUp(binding.binaryMessenger, notificationHost)
325+
DownloadManagerHostApi.setUp(binding.binaryMessenger, downloadHost)
298326
}
299327

300328
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
@@ -303,6 +331,9 @@ class ZulipPlugin : FlutterPlugin { // TODO ActivityAware too?
303331
return
304332
}
305333
AndroidNotificationHostApi.setUp(binding.binaryMessenger, null)
334+
DownloadManagerHostApi.setUp(binding.binaryMessenger, null)
335+
306336
notificationHost = null
337+
downloadHost = null
307338
}
308-
}
339+
}

assets/l10n/app_en.arb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,22 @@
751751
"@lightboxVideoDuration": {
752752
"description": "The total duration of the video playing in the lightbox."
753753
},
754+
"lightboxDownloadImageTooltip": "Download image",
755+
"@lightboxDownloadImageTooltip": {
756+
"description": "Tooltip in lightbox for the download image action."
757+
},
758+
"lightboxDownloadImageStarted": "Starting download...",
759+
"@lightboxDownloadImageStarted": {
760+
"description": "Message shown when the image download has started."
761+
},
762+
"lightboxDownloadImageFailed": "Failed to download the image.",
763+
"@lightboxDownloadImageFailed": {
764+
"description": "Message shown when the image download fails."
765+
},
766+
"lightboxDownloadImageError": "An error occurred while downloading the image.",
767+
"@lightboxDownloadImageError": {
768+
"description": "Message shown when an unexpected error occurs during image download."
769+
},
754770
"loginPageTitle": "Log in",
755771
"@loginPageTitle": {
756772
"description": "Title for login page."

lib/generated/l10n/zulip_localizations.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,30 @@ abstract class ZulipLocalizations {
11611161
/// **'Video duration'**
11621162
String get lightboxVideoDuration;
11631163

1164+
/// Tooltip in lightbox for the download image action.
1165+
///
1166+
/// In en, this message translates to:
1167+
/// **'Download image'**
1168+
String get lightboxDownloadImageTooltip;
1169+
1170+
/// Message shown when the image download has started.
1171+
///
1172+
/// In en, this message translates to:
1173+
/// **'Starting download...'**
1174+
String get lightboxDownloadImageStarted;
1175+
1176+
/// Message shown when the image download fails.
1177+
///
1178+
/// In en, this message translates to:
1179+
/// **'Failed to download the image.'**
1180+
String get lightboxDownloadImageFailed;
1181+
1182+
/// Message shown when an unexpected error occurs during image download.
1183+
///
1184+
/// In en, this message translates to:
1185+
/// **'An error occurred while downloading the image.'**
1186+
String get lightboxDownloadImageError;
1187+
11641188
/// Title for login page.
11651189
///
11661190
/// In en, this message translates to:

lib/generated/l10n/zulip_localizations_ar.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,19 @@ class ZulipLocalizationsAr extends ZulipLocalizations {
619619
@override
620620
String get lightboxVideoDuration => 'Video duration';
621621

622+
@override
623+
String get lightboxDownloadImageTooltip => 'Download image';
624+
625+
@override
626+
String get lightboxDownloadImageStarted => 'Starting download...';
627+
628+
@override
629+
String get lightboxDownloadImageFailed => 'Failed to download the image.';
630+
631+
@override
632+
String get lightboxDownloadImageError =>
633+
'An error occurred while downloading the image.';
634+
622635
@override
623636
String get loginPageTitle => 'Log in';
624637

lib/generated/l10n/zulip_localizations_de.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,19 @@ class ZulipLocalizationsDe extends ZulipLocalizations {
638638
@override
639639
String get lightboxVideoDuration => 'Videolänge';
640640

641+
@override
642+
String get lightboxDownloadImageTooltip => 'Download image';
643+
644+
@override
645+
String get lightboxDownloadImageStarted => 'Starting download...';
646+
647+
@override
648+
String get lightboxDownloadImageFailed => 'Failed to download the image.';
649+
650+
@override
651+
String get lightboxDownloadImageError =>
652+
'An error occurred while downloading the image.';
653+
641654
@override
642655
String get loginPageTitle => 'Anmelden';
643656

lib/generated/l10n/zulip_localizations_el.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,19 @@ class ZulipLocalizationsEl extends ZulipLocalizations {
619619
@override
620620
String get lightboxVideoDuration => 'Video duration';
621621

622+
@override
623+
String get lightboxDownloadImageTooltip => 'Download image';
624+
625+
@override
626+
String get lightboxDownloadImageStarted => 'Starting download...';
627+
628+
@override
629+
String get lightboxDownloadImageFailed => 'Failed to download the image.';
630+
631+
@override
632+
String get lightboxDownloadImageError =>
633+
'An error occurred while downloading the image.';
634+
622635
@override
623636
String get loginPageTitle => 'Log in';
624637

lib/generated/l10n/zulip_localizations_en.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,19 @@ class ZulipLocalizationsEn extends ZulipLocalizations {
619619
@override
620620
String get lightboxVideoDuration => 'Video duration';
621621

622+
@override
623+
String get lightboxDownloadImageTooltip => 'Download image';
624+
625+
@override
626+
String get lightboxDownloadImageStarted => 'Starting download...';
627+
628+
@override
629+
String get lightboxDownloadImageFailed => 'Failed to download the image.';
630+
631+
@override
632+
String get lightboxDownloadImageError =>
633+
'An error occurred while downloading the image.';
634+
622635
@override
623636
String get loginPageTitle => 'Log in';
624637

lib/generated/l10n/zulip_localizations_es.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,19 @@ class ZulipLocalizationsEs extends ZulipLocalizations {
619619
@override
620620
String get lightboxVideoDuration => 'Video duration';
621621

622+
@override
623+
String get lightboxDownloadImageTooltip => 'Download image';
624+
625+
@override
626+
String get lightboxDownloadImageStarted => 'Starting download...';
627+
628+
@override
629+
String get lightboxDownloadImageFailed => 'Failed to download the image.';
630+
631+
@override
632+
String get lightboxDownloadImageError =>
633+
'An error occurred while downloading the image.';
634+
622635
@override
623636
String get loginPageTitle => 'Log in';
624637

lib/generated/l10n/zulip_localizations_fr.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,19 @@ class ZulipLocalizationsFr extends ZulipLocalizations {
635635
@override
636636
String get lightboxVideoDuration => 'Video duration';
637637

638+
@override
639+
String get lightboxDownloadImageTooltip => 'Download image';
640+
641+
@override
642+
String get lightboxDownloadImageStarted => 'Starting download...';
643+
644+
@override
645+
String get lightboxDownloadImageFailed => 'Failed to download the image.';
646+
647+
@override
648+
String get lightboxDownloadImageError =>
649+
'An error occurred while downloading the image.';
650+
638651
@override
639652
String get loginPageTitle => 'Log in';
640653

0 commit comments

Comments
 (0)