This commit is contained in:
Hamza-Ayed
2025-09-01 18:29:05 +03:00
parent d71686d9f1
commit 6c87f7291d
33 changed files with 3118 additions and 7333 deletions

View File

@@ -28,13 +28,13 @@ class AboutPage extends StatelessWidget {
// Company Name and Introduction
Text(
'Tripz LLC',
'Intaleq LLC',
style: CupertinoTheme.of(context).textTheme.navTitleTextStyle,
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
Text(
'Egypt\'s pioneering ride-sharing service, proudly developed by Arabian and local owners. We prioritize being near you both our valued passengers and our dedicated captains.'
"Syria's pioneering ride-sharing service, proudly developed by Arabian and local owners. We prioritize being near you both our valued passengers and our dedicated captains."
.tr,
style: CupertinoTheme.of(context).textTheme.textStyle,
textAlign: TextAlign.center,
@@ -43,7 +43,7 @@ class AboutPage extends StatelessWidget {
// Key Features Section
Text(
'Why Choose Tripz?'.tr,
'Why Choose Intaleq?'.tr,
style: CupertinoTheme.of(context).textTheme.navTitleTextStyle,
textAlign: TextAlign.center,
),

View File

@@ -432,8 +432,7 @@ class ShareAppPage extends StatelessWidget {
),
),
Text(
controller.formatPhoneNumber(
contact['phones'][0].toString()),
(contact['phones'][0].toString()),
style: const TextStyle(
color: CupertinoColors.secondaryLabel,
fontSize: 15,

View File

@@ -1,5 +1,3 @@
import 'package:Intaleq/views/widgets/my_scafold.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:path/path.dart' as path;
@@ -8,205 +6,258 @@ import 'package:share_plus/share_plus.dart';
import '../../../controller/functions/audio_record1.dart';
class TripsRecordedPage extends StatelessWidget {
const TripsRecordedPage({
super.key,
});
const TripsRecordedPage({super.key});
@override
Widget build(BuildContext context) {
return MyScafolld(
title: 'Trips recorded'.tr,
body: [
GetBuilder<AudioRecorderController>(builder: (audio) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
FutureBuilder<List<String>>(
future: audio.getRecordedFiles(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CupertinoActivityIndicator());
} else if (snapshot.hasData) {
final recordedFiles = snapshot.data!;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: CupertinoButton(
padding: EdgeInsets.zero,
onPressed: () async {
String? selectedFile =
await showCupertinoModalPopup<String>(
context: context,
builder: (BuildContext context) {
return CupertinoActionSheet(
title: Text('Select a File'.tr),
actions: recordedFiles
.map(
(file) => CupertinoActionSheetAction(
child: Text(path.basename(file)),
onPressed: () {
Navigator.of(context).pop(file);
},
),
)
.toList(),
);
},
);
if (selectedFile != null) {
audio.selectedFilePath = selectedFile;
audio.playRecordedFile(selectedFile);
audio.update();
}
},
child: Text(
audio.selectedFilePath != null
? path.basename(audio.selectedFilePath!)
: 'Select a File'.tr,
style: CupertinoTheme.of(context)
.textTheme
.actionTextStyle
.copyWith(color: CupertinoColors.activeBlue),
),
),
);
} else {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Text('Error: ${snapshot.error}'),
);
}
},
),
// Ensure the controller is available.
// If it's not initialized elsewhere, you can use Get.put() or Get.lazyPut() here.
// Get.lazyPut(() => AudioRecorderController());
// Cupertino-style slider for seeking audio
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: CupertinoSlider(
value: audio.totalDuration > 0
? audio.currentPosition / audio.totalDuration
: 0.0, // Normalize to a value between 0.0 and 1.0
min: 0.0,
max: 1.0, // Maximum value is now 1.0
activeColor: CupertinoColors.activeBlue,
onChanged: (value) {
final newPosition = value * audio.totalDuration;
audio.currentPosition = newPosition;
audio.audioPlayer
.seek(Duration(seconds: newPosition.toInt()));
audio.update();
},
),
),
return Scaffold(
appBar: AppBar(
title: Text('Trips recorded'.tr),
backgroundColor: Colors.white,
elevation: 1,
actions: [
GetBuilder<AudioRecorderController>(
builder: (controller) => IconButton(
tooltip: 'Delete All'.tr,
icon: const Icon(Icons.delete_sweep_outlined),
onPressed: () {
_showDeleteConfirmation(context, controller, isDeleteAll: true);
},
),
)
],
),
body: GetBuilder<AudioRecorderController>(
builder: (controller) {
return Column(
children: [
Expanded(
child: _buildRecordingsList(controller),
),
// Show player controls only when a file is selected
if (controller.selectedFilePath != null)
_buildPlayerControls(context, controller),
],
);
},
),
);
}
// iOS-style playback controls
Padding(
padding: const EdgeInsets.symmetric(
vertical: 16.0, horizontal: 16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
CupertinoButton(
padding: EdgeInsets.zero,
child: Icon(
audio.isPlaying
? CupertinoIcons.pause
: CupertinoIcons.play_arrow,
color: CupertinoColors.activeBlue,
),
onPressed: () {
if (audio.isPlaying) {
audio.pausePlayback();
} else {
audio.resumePlayback();
}
audio.update();
},
),
CupertinoButton(
padding: EdgeInsets.zero,
child: const Icon(CupertinoIcons.stop,
color: CupertinoColors.destructiveRed),
onPressed: () {
audio.stopPlayback();
audio.update();
},
),
CupertinoButton(
padding: EdgeInsets.zero,
child: const Icon(CupertinoIcons.delete,
color: CupertinoColors.destructiveRed),
onPressed: () async {
showCupertinoModalPopup(
context: context,
builder: (BuildContext context) {
return CupertinoActionSheet(
title: Text('Are you sure?'.tr),
message: Text(
'This will delete all recorded files from your device.'
.tr,
textAlign: TextAlign.center,
),
actions: [
CupertinoActionSheetAction(
isDestructiveAction: true,
onPressed: () async {
await audio.deleteAllRecordedFiles();
Navigator.pop(context);
audio.update();
},
child: Text('Delete'.tr),
),
],
cancelButton: CupertinoActionSheetAction(
onPressed: () {
Navigator.pop(context);
},
child: Text('Cancel'.tr),
),
);
},
);
},
),
],
),
/// Builds the list of recorded audio files.
Widget _buildRecordingsList(AudioRecorderController controller) {
return FutureBuilder<List<String>>(
future: controller.getRecordedFiles(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'.tr));
}
if (!snapshot.hasData || snapshot.data!.isEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.mic_off_outlined, size: 80, color: Colors.grey[400]),
const SizedBox(height: 16),
Text(
'No Recordings Found'.tr,
style: TextStyle(fontSize: 18, color: Colors.grey[600]),
),
const SizedBox(height: 8),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 40.0),
child: Text(
'Record your trips to see them here.'.tr,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.grey[500]),
),
),
],
),
);
}
// File selection and sharing
if (audio.selectedFilePath != null)
Align(
alignment: Alignment.bottomCenter,
child: Container(
padding: const EdgeInsets.all(16.0),
color: CupertinoColors.systemGrey6,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Selected file: ${path.basename(audio.selectedFilePath!)}',
style: CupertinoTheme.of(context)
.textTheme
.textStyle,
),
CupertinoButton(
padding: EdgeInsets.zero,
child: const Icon(CupertinoIcons.share),
onPressed: () {
Share.shareXFiles(
[XFile(audio.selectedFilePath!)]);
},
),
],
),
),
),
],
final recordedFiles = snapshot.data!;
return ListView.builder(
padding: const EdgeInsets.only(top: 8, bottom: 8),
itemCount: recordedFiles.length,
itemBuilder: (context, index) {
final file = recordedFiles[index];
final fileName = path.basename(file);
final isSelected = controller.selectedFilePath == file;
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
elevation: isSelected ? 4 : 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12)),
child: ListTile(
leading: Icon(
isSelected && controller.isPlaying
? Icons.pause_circle_filled
: Icons.play_circle_fill,
color:
isSelected ? Theme.of(context).primaryColor : Colors.grey,
size: 40,
),
title: Text(fileName,
style: const TextStyle(fontWeight: FontWeight.w500)),
subtitle: Text("Audio Recording".tr),
onTap: () {
if (isSelected) {
controller.isPlaying
? controller.pausePlayback()
: controller.resumePlayback();
} else {
controller.playRecordedFile(file);
}
},
selected: isSelected,
selectedTileColor:
Theme.of(context).primaryColor.withOpacity(0.1),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12)),
),
);
})
],
isleading: true);
},
);
},
);
}
/// Builds the player UI at the bottom of the screen.
Widget _buildPlayerControls(
BuildContext context, AudioRecorderController controller) {
final fileName = path.basename(controller.selectedFilePath!);
final positionText = Duration(seconds: controller.currentPosition.toInt())
.toString()
.split('.')
.first
.padLeft(8, '0')
.substring(3);
final durationText = Duration(seconds: controller.totalDuration.toInt())
.toString()
.split('.')
.first
.padLeft(8, '0')
.substring(3);
return Material(
elevation: 10,
child: Container(
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(fileName,
style:
const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
textAlign: TextAlign.center),
const SizedBox(height: 8),
Row(
children: [
Text(positionText),
Expanded(
child: Slider(
value: (controller.totalDuration > 0)
? controller.currentPosition / controller.totalDuration
: 0.0,
onChanged: (value) {
final newPosition = value * controller.totalDuration;
controller.audioPlayer
.seek(Duration(seconds: newPosition.toInt()));
},
),
),
Text(durationText),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
icon: const Icon(Icons.share_outlined),
tooltip: 'Share'.tr,
onPressed: () {
Share.shareXFiles([XFile(controller.selectedFilePath!)]);
},
iconSize: 28,
),
IconButton(
icon: Icon(controller.isPlaying
? Icons.pause_circle_filled
: Icons.play_circle_filled),
onPressed: () {
controller.isPlaying
? controller.pausePlayback()
: controller.resumePlayback();
},
iconSize: 56,
color: Theme.of(context).primaryColor,
),
IconButton(
icon:
const Icon(Icons.delete_outline, color: Colors.redAccent),
tooltip: 'Delete'.tr,
onPressed: () {
_showDeleteConfirmation(context, controller,
isDeleteAll: false);
},
iconSize: 28,
),
],
)
],
),
),
);
}
/// Shows a confirmation dialog for deleting one or all files.
void _showDeleteConfirmation(
BuildContext context,
AudioRecorderController controller, {
required bool isDeleteAll,
}) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(isDeleteAll
? 'Delete All Recordings?'.tr
: 'Delete Recording?'.tr),
content: Text(isDeleteAll
? 'This action cannot be undone.'.tr
: 'Are you sure you want to delete this file?'.tr),
actions: [
TextButton(
child: Text('Cancel'.tr),
onPressed: () => Navigator.of(context).pop(),
),
TextButton(
child:
Text('Delete'.tr, style: const TextStyle(color: Colors.red)),
onPressed: () async {
if (isDeleteAll) {
await controller.deleteAllRecordedFiles();
} else {
// NOTE: You may need to add this method to your controller
// if it doesn't exist.
// await controller.deleteFile(controller.selectedFilePath!);
}
Navigator.of(context).pop();
},
),
],
);
},
);
}
}