Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Permissions for camera, microphone, and storage -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

<application
android:label="afochatapplication"
android:name="${applicationName}"
Expand Down
9 changes: 9 additions & 0 deletions ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,14 @@
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<!-- Camera and Microphone Permissions -->
<key>NSCameraUsageDescription</key>
<string>This app needs access to the camera to take photos and videos for sharing in chats.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app needs access to the microphone to record audio and video messages.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs access to your photo library to select photos and videos for sharing.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app needs permission to save photos and videos to your photo library.</string>
</dict>
</plist>
63 changes: 42 additions & 21 deletions lib/widgets/media_picker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ library;

import 'dart:io';

import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart' as picker;

import '../services/chat_service.dart';

Expand Down Expand Up @@ -136,13 +138,20 @@ class _MediaPickerWidgetState extends State<MediaPickerWidget>
/// Calls onMediaSelected callback with the selected image file
Future<void> _pickImage(ImageSource source) async {
try {
// Mock image picker implementation
// In production, use image_picker package
await Future.delayed(const Duration(milliseconds: 500));
final imagePicker = picker.ImagePicker();
final pickedFile = await imagePicker.pickImage(
source: source == ImageSource.camera
? picker.ImageSource.camera
: picker.ImageSource.gallery,
imageQuality: 85,
maxWidth: 1920,
maxHeight: 1920,
);

// For demonstration, create a mock image file
final mockImageFile = await _createMockFile('image.jpg', MessageType.image);
widget.onMediaSelected(mockImageFile, MessageType.image);
if (pickedFile != null) {
final file = File(pickedFile.path);
widget.onMediaSelected(file, MessageType.image);
}
} catch (e) {
_showError('Failed to pick image: $e');
}
Expand All @@ -160,12 +169,18 @@ class _MediaPickerWidgetState extends State<MediaPickerWidget>
/// Calls onMediaSelected callback with the selected video file
Future<void> _pickVideo(VideoSource source) async {
try {
// Mock video picker implementation
// In production, use image_picker package for videos
await Future.delayed(const Duration(milliseconds: 500));
final imagePicker = picker.ImagePicker();
final pickedFile = await imagePicker.pickVideo(
source: source == VideoSource.camera
? picker.ImageSource.camera
: picker.ImageSource.gallery,
maxDuration: const Duration(minutes: 5),
);

final mockVideoFile = await _createMockFile('video.mp4', MessageType.video);
widget.onMediaSelected(mockVideoFile, MessageType.video);
if (pickedFile != null) {
final file = File(pickedFile.path);
widget.onMediaSelected(file, MessageType.video);
}
} catch (e) {
_showError('Failed to pick video: $e');
}
Expand All @@ -182,12 +197,15 @@ class _MediaPickerWidgetState extends State<MediaPickerWidget>
/// Calls onMediaSelected callback with the selected document file
Future<void> _pickDocument() async {
try {
// Mock document picker implementation
// In production, use file_picker package
await Future.delayed(const Duration(milliseconds: 500));
final result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['pdf', 'doc', 'docx', 'txt', 'rtf', 'xls', 'xlsx', 'ppt', 'pptx'],
);

final mockDocFile = await _createMockFile('document.pdf', MessageType.document);
widget.onMediaSelected(mockDocFile, MessageType.document);
if (result != null && result.files.isNotEmpty) {
final file = File(result.files.single.path!);
widget.onMediaSelected(file, MessageType.document);
}
} catch (e) {
_showError('Failed to pick document: $e');
}
Expand All @@ -202,12 +220,15 @@ class _MediaPickerWidgetState extends State<MediaPickerWidget>
/// Calls onMediaSelected callback with the selected audio file
Future<void> _pickAudio() async {
try {
// Mock audio picker implementation
// In production, use file_picker package
await Future.delayed(const Duration(milliseconds: 500));
final result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['mp3', 'wav', 'aac', 'm4a', 'ogg', 'opus'],
);

final mockAudioFile = await _createMockFile('audio.mp3', MessageType.audio);
widget.onMediaSelected(mockAudioFile, MessageType.audio);
if (result != null && result.files.isNotEmpty) {
final file = File(result.files.single.path!);
widget.onMediaSelected(file, MessageType.audio);
}
} catch (e) {
_showError('Failed to pick audio: $e');
}
Expand Down
Loading