Last active
February 4, 2025 09:35
-
-
Save ponnamkarthik/8ea95d514e882552f22e4c3cb876599e to your computer and use it in GitHub Desktop.
Flutter DirectoryListing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> | |
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | |
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> | |
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/> | |
<application | |
android:requestLegacyExternalStorage="true" | |
android:label="directorylisting" | |
android:name="${applicationName}" | |
android:icon="@mipmap/ic_launcher"> | |
<activity | |
android:name=".MainActivity" | |
android:exported="true" | |
android:launchMode="singleTop" | |
android:taskAffinity="" | |
android:theme="@style/LaunchTheme" | |
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" | |
android:hardwareAccelerated="true" | |
android:windowSoftInputMode="adjustResize"> | |
<!-- Specifies an Android theme to apply to this Activity as soon as | |
the Android process has started. This theme is visible to the user | |
while the Flutter UI initializes. After that, this theme continues | |
to determine the Window background behind the Flutter UI. --> | |
<meta-data | |
android:name="io.flutter.embedding.android.NormalTheme" | |
android:resource="@style/NormalTheme" | |
/> | |
<intent-filter> | |
<action android:name="android.intent.action.MAIN"/> | |
<category android:name="android.intent.category.LAUNCHER"/> | |
</intent-filter> | |
</activity> | |
<!-- Don't delete the meta-data below. | |
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> | |
<meta-data | |
android:name="flutterEmbedding" | |
android:value="2" /> | |
</application> | |
<!-- Required to query activities that can process text, see: | |
https://developer.android.com/training/package-visibility and | |
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT. | |
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. --> | |
<queries> | |
<intent> | |
<action android:name="android.intent.action.PROCESS_TEXT"/> | |
<data android:mimeType="text/plain"/> | |
</intent> | |
</queries> | |
</manifest> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'dart:io'; | |
import 'package:permission_handler/permission_handler.dart'; | |
void main() { | |
runApp(const MyApp()); | |
} | |
class FileSystemItem { | |
final String path; | |
final bool isFolder; | |
final String title; | |
final List<FileSystemItem>? children; | |
FileSystemItem({ | |
required this.path, | |
required this.isFolder, | |
required this.title, | |
this.children, | |
}); | |
} | |
Future<List<FileSystemItem>> getDirectoryStructure(String dirPath) async { | |
final dir = Directory(dirPath); | |
if (!await dir.exists()) { | |
return []; | |
} | |
return _getStructure(dir); | |
} | |
Future<List<FileSystemItem>> _getStructure(Directory dir) async { | |
final List<FileSystemItem> structure = []; | |
final List<FileSystemEntity> entities = dir.listSync(); | |
for (var entity in entities) { | |
if (entity.path.contains("Android")) { | |
continue; | |
} | |
final isFolder = entity is Directory; | |
final path = entity.path; | |
final title = path.split('/').last; | |
structure.add(FileSystemItem( | |
path: path, | |
isFolder: isFolder, | |
title: title, | |
children: isFolder ? await _getStructure(Directory(path)) : null, | |
)); | |
} | |
return structure; | |
} | |
class FileExplorerScreen extends StatelessWidget { | |
final String path; | |
FileExplorerScreen({required this.path}); | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar(title: Text(path.split('/').last)), | |
body: FutureBuilder<List<FileSystemItem>>( | |
future: getDirectoryStructure(path), | |
builder: (context, snapshot) { | |
if (snapshot.connectionState == ConnectionState.waiting) { | |
return Center(child: CircularProgressIndicator()); | |
} | |
if (!snapshot.hasData || snapshot.data!.isEmpty) { | |
return Center(child: Text("No files found")); | |
} | |
return ListView.builder( | |
itemCount: snapshot.data!.length, | |
itemBuilder: (context, index) { | |
final item = snapshot.data![index]; | |
return ListTile( | |
leading: Icon( | |
item.isFolder ? Icons.folder : Icons.insert_drive_file), | |
title: Text(item.title), | |
onTap: item.isFolder | |
? () { | |
Navigator.push( | |
context, | |
MaterialPageRoute( | |
builder: (context) => | |
FileExplorerScreen(path: item.path), | |
), | |
); | |
} | |
: () { | |
SnackBar snackBar = SnackBar( | |
content: Text("File: ${item.title}"), | |
); | |
ScaffoldMessenger.of(context).showSnackBar(snackBar); | |
}, | |
); | |
}, | |
); | |
}, | |
), | |
); | |
} | |
} | |
class MyApp extends StatefulWidget { | |
const MyApp({super.key}); | |
@override | |
State<MyApp> createState() => _MyAppState(); | |
} | |
class _MyAppState extends State<MyApp> { | |
bool isStoragePermissionGranted = false; | |
Future<void> requestStoragePermission() async { | |
if (Platform.isAndroid) { | |
if (await Permission.storage.request().isGranted) { | |
setState(() { | |
isStoragePermissionGranted = true; | |
}); | |
} else if (await Permission.manageExternalStorage.request().isGranted) { | |
setState(() { | |
isStoragePermissionGranted = true; | |
}); | |
} else { | |
setState(() { | |
isStoragePermissionGranted = false; | |
}); | |
} | |
} else { | |
setState(() { | |
isStoragePermissionGranted = true; | |
}); | |
} | |
} | |
@override | |
void initState() { | |
super.initState(); | |
requestStoragePermission(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'Flutter Demo', | |
theme: ThemeData( | |
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), | |
useMaterial3: true, | |
), | |
home: isStoragePermissionGranted | |
? FileExplorerScreen(path: "/storage/emulated/0/") | |
: Scaffold( | |
body: Center( | |
child: ElevatedButton( | |
onPressed: requestStoragePermission, | |
child: Text("Grant Storage Permission"), | |
), | |
), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment