Skip to content

Commit f7d4a96

Browse files
committed
chore: revert #16732
1 parent f659ef4 commit f7d4a96

File tree

14 files changed

+17
-395
lines changed

14 files changed

+17
-395
lines changed

mobile/android/app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
android:maxSdkVersion="32" />
77
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
88
android:maxSdkVersion="32" />
9-
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
109
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
1110
<uses-permission android:name="android.permission.MANAGE_MEDIA" />
1211
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
@@ -125,4 +124,4 @@
125124
<data android:scheme="geo" />
126125
</intent>
127126
</queries>
128-
</manifest>
127+
</manifest>
Lines changed: 7 additions & 199 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,25 @@
11
package app.alextran.immich
22

3-
import android.content.ContentResolver
4-
import android.content.ContentUris
5-
import android.content.ContentValues
63
import android.content.Context
7-
import android.content.Intent
8-
import android.net.Uri
9-
import android.os.Build
10-
import android.os.Bundle
11-
import android.os.Environment
12-
import android.provider.MediaStore
13-
import android.provider.Settings
144
import android.util.Log
155
import io.flutter.embedding.engine.plugins.FlutterPlugin
16-
import io.flutter.embedding.engine.plugins.activity.ActivityAware
17-
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
186
import io.flutter.plugin.common.BinaryMessenger
197
import io.flutter.plugin.common.MethodCall
208
import io.flutter.plugin.common.MethodChannel
21-
import io.flutter.plugin.common.MethodChannel.Result
22-
import io.flutter.plugin.common.PluginRegistry
239
import java.security.MessageDigest
2410
import java.io.FileInputStream
2511
import kotlinx.coroutines.*
2612

2713
/**
28-
* Android plugin for Dart `BackgroundService` and file trash operations
14+
* Android plugin for Dart `BackgroundService`
15+
*
16+
* Receives messages/method calls from the foreground Dart side to manage
17+
* the background service, e.g. start (enqueue), stop (cancel)
2918
*/
30-
class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware, PluginRegistry.ActivityResultListener {
19+
class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
3120

3221
private var methodChannel: MethodChannel? = null
33-
private var fileTrashChannel: MethodChannel? = null
3422
private var context: Context? = null
35-
private var pendingResult: Result? = null
36-
private val PERMISSION_REQUEST_CODE = 1001
37-
private var activityBinding: ActivityPluginBinding? = null
3823

3924
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
4025
onAttachedToEngine(binding.applicationContext, binding.binaryMessenger)
@@ -44,10 +29,6 @@ class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
4429
context = ctx
4530
methodChannel = MethodChannel(messenger, "immich/foregroundChannel")
4631
methodChannel?.setMethodCallHandler(this)
47-
48-
// Add file trash channel
49-
fileTrashChannel = MethodChannel(messenger, "file_trash")
50-
fileTrashChannel?.setMethodCallHandler(this)
5132
}
5233

5334
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
@@ -57,14 +38,11 @@ class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
5738
private fun onDetachedFromEngine() {
5839
methodChannel?.setMethodCallHandler(null)
5940
methodChannel = null
60-
fileTrashChannel?.setMethodCallHandler(null)
61-
fileTrashChannel = null
6241
}
6342

64-
override fun onMethodCall(call: MethodCall, result: Result) {
43+
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
6544
val ctx = context!!
6645
when (call.method) {
67-
// Existing BackgroundService methods
6846
"enable" -> {
6947
val args = call.arguments<ArrayList<*>>()!!
7048
ctx.getSharedPreferences(BackupWorker.SHARED_PREF_NAME, Context.MODE_PRIVATE)
@@ -136,180 +114,10 @@ class BackgroundServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
136114
}
137115
}
138116

139-
// File Trash methods moved from MainActivity
140-
"moveToTrash" -> {
141-
val fileName = call.argument<String>("fileName")
142-
if (fileName != null) {
143-
if (hasManageStoragePermission()) {
144-
val success = moveToTrash(fileName)
145-
result.success(success)
146-
} else {
147-
result.error("PERMISSION_DENIED", "Storage permission required", null)
148-
}
149-
} else {
150-
result.error("INVALID_NAME", "The file name is not specified.", null)
151-
}
152-
}
153-
154-
"restoreFromTrash" -> {
155-
val fileName = call.argument<String>("fileName")
156-
if (fileName != null) {
157-
if (hasManageStoragePermission()) {
158-
val success = untrashImage(fileName)
159-
result.success(success)
160-
} else {
161-
result.error("PERMISSION_DENIED", "Storage permission required", null)
162-
}
163-
} else {
164-
result.error("INVALID_NAME", "The file name is not specified.", null)
165-
}
166-
}
167-
168-
"requestManageStoragePermission" -> {
169-
if (!hasManageStoragePermission()) {
170-
requestManageStoragePermission(result)
171-
} else {
172-
Log.e("Manage storage permission", "Permission already granted")
173-
result.success(true)
174-
}
175-
}
176-
177117
else -> result.notImplemented()
178118
}
179119
}
180-
181-
// File Trash methods moved from MainActivity
182-
private fun hasManageStoragePermission(): Boolean {
183-
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
184-
Environment.isExternalStorageManager()
185-
} else {
186-
true
187-
}
188-
}
189-
190-
private fun requestManageStoragePermission(result: Result) {
191-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
192-
pendingResult = result // Store the result callback
193-
val activity = activityBinding?.activity ?: return
194-
195-
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
196-
intent.data = Uri.parse("package:${activity.packageName}")
197-
activity.startActivityForResult(intent, PERMISSION_REQUEST_CODE)
198-
} else {
199-
result.success(true)
200-
}
201-
}
202-
203-
private fun moveToTrash(fileName: String): Boolean {
204-
val contentResolver = context?.contentResolver ?: return false
205-
val uri = getFileUri(fileName)
206-
Log.e("FILE_URI", uri.toString())
207-
return uri?.let { moveToTrash(it) } ?: false
208-
}
209-
210-
private fun moveToTrash(contentUri: Uri): Boolean {
211-
val contentResolver = context?.contentResolver ?: return false
212-
return try {
213-
val values = ContentValues().apply {
214-
put(MediaStore.MediaColumns.IS_TRASHED, 1) // Move to trash
215-
}
216-
val updated = contentResolver.update(contentUri, values, null, null)
217-
updated > 0
218-
} catch (e: Exception) {
219-
Log.e("TrashError", "Error moving to trash", e)
220-
false
221-
}
222-
}
223-
224-
private fun getFileUri(fileName: String): Uri? {
225-
val contentResolver = context?.contentResolver ?: return null
226-
val contentUri = MediaStore.Files.getContentUri("external")
227-
val projection = arrayOf(MediaStore.Images.Media._ID)
228-
val selection = "${MediaStore.Images.Media.DISPLAY_NAME} = ?"
229-
val selectionArgs = arrayOf(fileName)
230-
var fileUri: Uri? = null
231-
232-
contentResolver.query(contentUri, projection, selection, selectionArgs, null)?.use { cursor ->
233-
if (cursor.moveToFirst()) {
234-
val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID))
235-
fileUri = ContentUris.withAppendedId(contentUri, id)
236-
}
237-
}
238-
return fileUri
239-
}
240-
241-
private fun untrashImage(name: String): Boolean {
242-
val contentResolver = context?.contentResolver ?: return false
243-
val uri = getTrashedFileUri(contentResolver, name)
244-
Log.e("FILE_URI", uri.toString())
245-
return uri?.let { untrashImage(it) } ?: false
246-
}
247-
248-
private fun untrashImage(contentUri: Uri): Boolean {
249-
val contentResolver = context?.contentResolver ?: return false
250-
return try {
251-
val values = ContentValues().apply {
252-
put(MediaStore.MediaColumns.IS_TRASHED, 0) // Restore file
253-
}
254-
val updated = contentResolver.update(contentUri, values, null, null)
255-
updated > 0
256-
} catch (e: Exception) {
257-
Log.e("TrashError", "Error restoring file", e)
258-
false
259-
}
260-
}
261-
262-
private fun getTrashedFileUri(contentResolver: ContentResolver, fileName: String): Uri? {
263-
val contentUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL)
264-
val projection = arrayOf(MediaStore.Files.FileColumns._ID)
265-
266-
val queryArgs = Bundle().apply {
267-
putString(ContentResolver.QUERY_ARG_SQL_SELECTION, "${MediaStore.Files.FileColumns.DISPLAY_NAME} = ?")
268-
putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS, arrayOf(fileName))
269-
putInt(MediaStore.QUERY_ARG_MATCH_TRASHED, MediaStore.MATCH_ONLY)
270-
}
271-
272-
contentResolver.query(contentUri, projection, queryArgs, null)?.use { cursor ->
273-
if (cursor.moveToFirst()) {
274-
val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID))
275-
return ContentUris.withAppendedId(contentUri, id)
276-
}
277-
}
278-
return null
279-
}
280-
281-
// ActivityAware implementation
282-
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
283-
activityBinding = binding
284-
binding.addActivityResultListener(this)
285-
}
286-
287-
override fun onDetachedFromActivityForConfigChanges() {
288-
activityBinding?.removeActivityResultListener(this)
289-
activityBinding = null
290-
}
291-
292-
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
293-
activityBinding = binding
294-
binding.addActivityResultListener(this)
295-
}
296-
297-
override fun onDetachedFromActivity() {
298-
activityBinding?.removeActivityResultListener(this)
299-
activityBinding = null
300-
}
301-
302-
// ActivityResultListener implementation
303-
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
304-
if (requestCode == PERMISSION_REQUEST_CODE) {
305-
val granted = hasManageStoragePermission()
306-
pendingResult?.success(granted)
307-
pendingResult = null
308-
return true
309-
}
310-
return false
311-
}
312120
}
313121

314122
private const val TAG = "BackgroundServicePlugin"
315-
private const val BUFFER_SIZE = 2 * 1024 * 1024
123+
private const val BUFFER_SIZE = 2 * 1024 * 1024;

mobile/android/app/src/main/kotlin/app/alextran/immich/MainActivity.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ package app.alextran.immich
22

33
import io.flutter.embedding.android.FlutterActivity
44
import io.flutter.embedding.engine.FlutterEngine
5-
import androidx.annotation.NonNull
5+
import android.os.Bundle
6+
import android.content.Intent
67

78
class MainActivity : FlutterActivity() {
8-
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
9+
10+
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
911
super.configureFlutterEngine(flutterEngine)
1012
flutterEngine.plugins.add(BackgroundServicePlugin())
11-
// No need to set up method channel here as it's now handled in the plugin
1213
}
14+
1315
}

mobile/lib/domain/models/store.model.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ enum StoreKey<T> {
6565

6666
// Video settings
6767
loadOriginalVideo<bool>._(136),
68-
manageLocalMediaAndroid<bool>._(137),
6968

7069
// Experimental stuff
7170
photoManagerCustomFilter<bool>._(1000);

mobile/lib/interfaces/local_files_manager.interface.dart

Lines changed: 0 additions & 5 deletions
This file was deleted.

mobile/lib/providers/websocket.provider.dart

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ enum PendingAction {
2323
assetDelete,
2424
assetUploaded,
2525
assetHidden,
26-
assetTrash,
2726
}
2827

2928
class PendingChange {
@@ -161,7 +160,7 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
161160
socket.on('on_upload_success', _handleOnUploadSuccess);
162161
socket.on('on_config_update', _handleOnConfigUpdate);
163162
socket.on('on_asset_delete', _handleOnAssetDelete);
164-
socket.on('on_asset_trash', _handleOnAssetTrash);
163+
socket.on('on_asset_trash', _handleServerUpdates);
165164
socket.on('on_asset_restore', _handleServerUpdates);
166165
socket.on('on_asset_update', _handleServerUpdates);
167166
socket.on('on_asset_stack_update', _handleServerUpdates);
@@ -208,26 +207,6 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
208207
_debounce.run(handlePendingChanges);
209208
}
210209

211-
Future<void> _handlePendingTrashes() async {
212-
final trashChanges = state.pendingChanges
213-
.where((c) => c.action == PendingAction.assetTrash)
214-
.toList();
215-
if (trashChanges.isNotEmpty) {
216-
List<String> remoteIds = trashChanges
217-
.expand((a) => (a.value as List).map((e) => e.toString()))
218-
.toList();
219-
220-
await _ref.read(syncServiceProvider).handleRemoteAssetRemoval(remoteIds);
221-
await _ref.read(assetProvider.notifier).getAllAsset();
222-
223-
state = state.copyWith(
224-
pendingChanges: state.pendingChanges
225-
.whereNot((c) => trashChanges.contains(c))
226-
.toList(),
227-
);
228-
}
229-
}
230-
231210
Future<void> _handlePendingDeletes() async {
232211
final deleteChanges = state.pendingChanges
233212
.where((c) => c.action == PendingAction.assetDelete)
@@ -288,7 +267,6 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
288267
await _handlePendingUploaded();
289268
await _handlePendingDeletes();
290269
await _handlingPendingHidden();
291-
await _handlePendingTrashes();
292270
}
293271

294272
void _handleOnConfigUpdate(dynamic _) {
@@ -307,10 +285,6 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
307285
void _handleOnAssetDelete(dynamic data) =>
308286
addPendingChange(PendingAction.assetDelete, data);
309287

310-
void _handleOnAssetTrash(dynamic data) {
311-
addPendingChange(PendingAction.assetTrash, data);
312-
}
313-
314288
void _handleOnAssetHidden(dynamic data) =>
315289
addPendingChange(PendingAction.assetHidden, data);
316290

mobile/lib/repositories/local_files_manager.repository.dart

Lines changed: 0 additions & 23 deletions
This file was deleted.

mobile/lib/services/app_settings.service.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ enum AppSettingsEnum<T> {
6161
0,
6262
),
6363
advancedTroubleshooting<bool>(StoreKey.advancedTroubleshooting, null, false),
64-
manageLocalMediaAndroid<bool>(StoreKey.manageLocalMediaAndroid, null, false),
6564
logLevel<int>(StoreKey.logLevel, null, 5), // Level.INFO = 5
6665
preferRemoteImage<bool>(StoreKey.preferRemoteImage, null, false),
6766
loopVideo<bool>(StoreKey.loopVideo, "loopVideo", true),

0 commit comments

Comments
 (0)