Created
December 6, 2024 07:20
-
-
Save jezell/a40a879bd984aadd8ea9d6b705a859f0 to your computer and use it in GitHub Desktop.
o1 pro slides from json test
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 'package:audioplayers/audioplayers.dart'; | |
class TextSlide { | |
/// Hex color for the text. Defaults to white (#ffffff) if missing or empty. | |
final String textColor; | |
/// Title of the slide. Defaults to empty string if missing. | |
final String title; | |
/// Bulleted text content. Defaults to empty string if missing. | |
final String text; | |
/// Background image URL. Defaults to empty string if missing. | |
final String background; | |
/// Voiceover text. Defaults to empty string if missing. | |
/// (Not displayed, but may be used for other logic if needed.) | |
final String voiceover; | |
/// Voiceover audio URL or asset path. Defaults to empty if missing. | |
final String voiceoverAudio; | |
TextSlide({ | |
required this.textColor, | |
required this.title, | |
required this.text, | |
required this.background, | |
required this.voiceover, | |
required this.voiceoverAudio, | |
}); | |
factory TextSlide.fromJson(Map<String, dynamic> json) { | |
return TextSlide( | |
textColor: (json['textColor'] as String?)?.isNotEmpty == true | |
? json['textColor'] as String | |
: '#ffffff', | |
title: (json['title'] as String?) ?? '', | |
text: (json['text'] as String?) ?? '', | |
background: (json['background'] as String?) ?? '', | |
voiceover: (json['voiceover'] as String?) ?? '', | |
voiceoverAudio: (json['voiceover_audio'] as String?) ?? '', | |
); | |
} | |
Map<String, dynamic> toJson() { | |
return { | |
'textColor': textColor, | |
'title': title, | |
'text': text, | |
'background': background, | |
'voiceover': voiceover, | |
'voiceover_audio': voiceoverAudio, | |
}; | |
} | |
} | |
class SlideData { | |
final TextSlide textSlide; | |
SlideData({required this.textSlide}); | |
factory SlideData.fromJson(Map<String, dynamic> json) { | |
return SlideData( | |
textSlide: TextSlide.fromJson(json['text_slide'] as Map<String, dynamic>), | |
); | |
} | |
Map<String, dynamic> toJson() { | |
return { | |
'text_slide': textSlide.toJson(), | |
}; | |
} | |
} | |
class TextSlideWidget extends StatefulWidget { | |
final SlideData slideData; | |
const TextSlideWidget({Key? key, required this.slideData}) : super(key: key); | |
@override | |
State<TextSlideWidget> createState() => _TextSlideWidgetState(); | |
} | |
class _TextSlideWidgetState extends State<TextSlideWidget> { | |
final AudioPlayer _audioPlayer = AudioPlayer(); | |
@override | |
void initState() { | |
super.initState(); | |
_playVoiceoverIfAvailable(); | |
} | |
Future<void> _playVoiceoverIfAvailable() async { | |
final voiceoverAudio = widget.slideData.textSlide.voiceoverAudio; | |
if (voiceoverAudio.isNotEmpty) { | |
await _audioPlayer.play(UrlSource(voiceoverAudio)); | |
} | |
} | |
@override | |
void dispose() { | |
_audioPlayer.dispose(); | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
final ts = widget.slideData.textSlide; | |
final textColor = _fromHex(ts.textColor); | |
return Stack( | |
fit: StackFit.expand, | |
children: [ | |
// Background image or fallback | |
if (ts.background.isNotEmpty) | |
Image.network( | |
ts.background, | |
fit: BoxFit.cover, | |
) | |
else | |
Container(color: Colors.black), | |
// Optional gradient overlay for readability | |
Container( | |
decoration: BoxDecoration( | |
gradient: LinearGradient( | |
colors: [Colors.black.withOpacity(0.3), Colors.black.withOpacity(0.7)], | |
begin: Alignment.topCenter, | |
end: Alignment.bottomCenter, | |
), | |
), | |
), | |
// Slide content | |
SafeArea( | |
child: Padding( | |
padding: const EdgeInsets.all(16.0), | |
child: SingleChildScrollView( | |
child: Column( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: [ | |
if (ts.title.isNotEmpty) | |
Text( | |
ts.title, | |
style: TextStyle( | |
color: textColor, | |
fontSize: 28, | |
fontWeight: FontWeight.bold, | |
), | |
), | |
const SizedBox(height: 16), | |
if (ts.text.isNotEmpty) | |
_buildBulletList(ts.text, textColor), | |
], | |
), | |
), | |
), | |
), | |
], | |
); | |
} | |
Widget _buildBulletList(String text, Color textColor) { | |
final lines = text.split('\n').where((line) => line.trim().isNotEmpty); | |
return Column( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: lines.map((line) { | |
final trimmedLine = line.trim().replaceFirst(RegExp(r'^- '), ''); | |
return Padding( | |
padding: const EdgeInsets.symmetric(vertical: 4.0), | |
child: Row( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: [ | |
Text( | |
'• ', | |
style: TextStyle(color: textColor, fontSize: 18, fontWeight: FontWeight.bold), | |
), | |
Expanded( | |
child: Text( | |
trimmedLine, | |
style: TextStyle(color: textColor, fontSize: 16), | |
), | |
), | |
], | |
), | |
); | |
}).toList(), | |
); | |
} | |
Color _fromHex(String hexCode) { | |
final buffer = StringBuffer(); | |
if (hexCode.length == 7) buffer.write('ff'); | |
buffer.write(hexCode.replaceFirst('#', '')); | |
return Color(int.parse(buffer.toString(), radix: 16)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment