added multimedia support and STT. STT and photos are have bugs but are functional. file upload is conceptualized but will require additional backend work. video is on hold for now.

This commit is contained in:
Joshua
2024-07-10 19:15:03 -06:00
parent e5b69aa2b6
commit cbd040f57b
36 changed files with 742 additions and 137 deletions
@@ -0,0 +1,496 @@
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import '../components/support_form_model.dart';
export '../components/support_form_model.dart';
import 'package:app/theme.dart';
class SupportFormWidget extends StatefulWidget {
const SupportFormWidget({super.key});
@override
State<SupportFormWidget> createState() => _SupportFormWidgetState();
}
class _SupportFormWidgetState extends State<SupportFormWidget>
with TickerProviderStateMixin {
late SupportFormModel _model;
final scaffoldKey = GlobalKey<ScaffoldState>();
final animationsMap = <String, AnimationInfo>{};
@override
void initState() {
super.initState();
_model = createModel(context, () => SupportFormModel());
_model.textController1 ??= TextEditingController();
_model.textFieldFocusNode1 ??= FocusNode();
_model.textController2 ??= TextEditingController();
_model.textFieldFocusNode2 ??= FocusNode();
_model.textController3 ??= TextEditingController();
_model.textFieldFocusNode3 ??= FocusNode();
animationsMap.addAll({
'containerOnPageLoadAnimation1': AnimationInfo(
trigger: AnimationTrigger.onPageLoad,
effectsBuilder: () => [
FadeEffect(
curve: Curves.easeInOut,
delay: 0.0.ms,
duration: 600.0.ms,
begin: 0.0,
end: 1.0,
),
MoveEffect(
curve: Curves.easeInOut,
delay: 0.0.ms,
duration: 600.0.ms,
begin: const Offset(0.0, 110.0),
end: const Offset(0.0, 0.0),
),
],
),
'containerOnPageLoadAnimation2': AnimationInfo(
trigger: AnimationTrigger.onPageLoad,
effectsBuilder: () => [
FadeEffect(
curve: Curves.easeInOut,
delay: 0.0.ms,
duration: 600.0.ms,
begin: 0.0,
end: 1.0,
),
MoveEffect(
curve: Curves.easeInOut,
delay: 0.0.ms,
duration: 600.0.ms,
begin: const Offset(0.0, 110.0),
end: const Offset(0.0, 0.0),
),
],
),
'containerOnPageLoadAnimation3': AnimationInfo(
trigger: AnimationTrigger.onPageLoad,
effectsBuilder: () => [
FadeEffect(
curve: Curves.easeInOut,
delay: 0.0.ms,
duration: 600.0.ms,
begin: 0.0,
end: 1.0,
),
MoveEffect(
curve: Curves.easeInOut,
delay: 0.0.ms,
duration: 600.0.ms,
begin: const Offset(0.0, 110.0),
end: const Offset(0.0, 0.0),
),
],
),
});
setupAnimations(
animationsMap.values.where((anim) =>
anim.trigger == AnimationTrigger.onActionTrigger ||
!anim.applyInitialState),
this,
);
}
@override
void dispose() {
_model.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => _model.unfocusNode.canRequestFocus
? FocusScope.of(context).requestFocus(_model.unfocusNode)
: FocusScope.of(context).unfocus(),
child: Scaffold(
key: scaffoldKey,
backgroundColor: AppTheme.secondaryBackground,
appBar: AppBar(
backgroundColor: AppTheme.secondaryBackground,
automaticallyImplyLeading: false,
leading: FlutterFlowIconButton(
borderColor: Colors.transparent,
borderRadius: 30,
borderWidth: 1,
buttonSize: 60,
icon: const Icon(
Icons.arrow_back_rounded,
color: AppTheme.primaryTextColor,
size: 30,
),
onPressed: () async {
//TODO: context.pop();
},
),
title: const Text(
'Submit Ticket',
style: AppTheme.titleLarge,
),
actions: const [],
centerTitle: false,
elevation: 0,
),
body: SafeArea(
top: true,
child: Align(
alignment: const AlignmentDirectional(0, 1),
child: Padding(
padding: const EdgeInsetsDirectional.fromSTEB(16, 12, 16, 0),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Welcome to support',
style: AppTheme.labelLarge,
),
const Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 4, 0, 0),
child: Text(
'Submit a bug',
style: AppTheme.headlineMedium,
),
),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: Padding(
padding:
const EdgeInsetsDirectional.fromSTEB(0, 16, 0, 0),
child: Container(
width: 120,
constraints: const BoxConstraints(
maxWidth: 500,
),
decoration: BoxDecoration(
color: AppTheme
.secondaryBackground,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: AppTheme.alternate,
width: 2,
),
),
child: const Padding(
padding: EdgeInsetsDirectional.fromSTEB(
8, 16, 8, 16),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
Icons.email_outlined,
color:
AppTheme.primary,
size: 36,
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0, 12, 0, 0),
child: Text(
'Email Us',
textAlign: TextAlign.center,
style: AppTheme.bodyMedium,
),
),
],
),
),
).animateOnPageLoad(animationsMap[
'containerOnPageLoadAnimation1']!),
),
),
Expanded(
child: Padding(
padding:
const EdgeInsetsDirectional.fromSTEB(0, 16, 0, 0),
child: Container(
width: 120,
constraints: const BoxConstraints(
maxWidth: 500,
),
decoration: BoxDecoration(
color: AppTheme
.secondaryBackground,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: AppTheme.alternate,
width: 2,
),
),
child: const Padding(
padding: EdgeInsetsDirectional.fromSTEB(
8, 16, 8, 16),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
Icons.search_rounded,
color:
AppTheme.primary,
size: 36,
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0, 12, 0, 0),
child: Text(
'Search FAQs',
textAlign: TextAlign.center,
style: AppTheme.bodyMedium,
),
),
],
),
),
).animateOnPageLoad(animationsMap[
'containerOnPageLoadAnimation2']!),
),
),
].divide(const SizedBox(width: 12)),
),
Padding(
padding: const EdgeInsetsDirectional.fromSTEB(0, 16, 0, 0),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
TextFormField(
controller: _model.textController1,
focusNode: _model.textFieldFocusNode1,
autofocus: true,
obscureText: false,
decoration: InputDecoration(
labelText: 'Channel Name',
labelStyle: AppTheme.labelMedium,
hintStyle: AppTheme.labelMedium,
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: AppTheme.alternate,
width: 2,
),
borderRadius: BorderRadius.circular(12),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: AppTheme.primary,
width: 2,
),
borderRadius: BorderRadius.circular(12),
),
errorBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: AppTheme.error,
width: 2,
),
borderRadius: BorderRadius.circular(12),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: AppTheme.error,
width: 2,
),
borderRadius: BorderRadius.circular(12),
),
contentPadding: const EdgeInsetsDirectional.fromSTEB(
16, 12, 16, 12),
),
style: AppTheme.bodyMedium,
cursorColor: AppTheme.primary,
validator: _model.textController1Validator
.asValidator(context),
),
TextFormField(
controller: _model.textController2,
focusNode: _model.textFieldFocusNode2,
autofocus: true,
obscureText: false,
decoration: InputDecoration(
labelText: 'Channel ID',
labelStyle: AppTheme.labelMedium,
hintStyle: AppTheme.labelMedium,
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: AppTheme.alternate,
width: 2,
),
borderRadius: BorderRadius.circular(12),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: AppTheme.primary,
width: 2,
),
borderRadius: BorderRadius.circular(12),
),
errorBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: AppTheme.error,
width: 2,
),
borderRadius: BorderRadius.circular(12),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: AppTheme.error,
width: 2,
),
borderRadius: BorderRadius.circular(12),
),
contentPadding: const EdgeInsetsDirectional.fromSTEB(
16, 12, 16, 12),
),
style: AppTheme.bodyMedium,
cursorColor: AppTheme.primary,
validator: _model.textController2Validator
.asValidator(context),
),
TextFormField(
controller: _model.textController3,
focusNode: _model.textFieldFocusNode3,
autofocus: true,
obscureText: false,
decoration: InputDecoration(
labelStyle: AppTheme.labelMedium,
hintText:
'Short Description of what is going on...',
hintStyle: AppTheme.labelMedium,
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: AppTheme.alternate,
width: 2,
),
borderRadius: BorderRadius.circular(12),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: AppTheme.primary,
width: 2,
),
borderRadius: BorderRadius.circular(12),
),
errorBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: AppTheme.error,
width: 2,
),
borderRadius: BorderRadius.circular(12),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: AppTheme.error,
width: 2,
),
borderRadius: BorderRadius.circular(12),
),
contentPadding: const EdgeInsetsDirectional.fromSTEB(
16, 24, 16, 12),
),
style: AppTheme.bodyMedium,
maxLines: 16,
minLines: 6,
cursorColor: AppTheme.primary,
validator: _model.textController3Validator
.asValidator(context),
),
].divide(const SizedBox(height: 12)),
),
),
Padding(
padding: const EdgeInsetsDirectional.fromSTEB(0, 16, 0, 0),
child: Container(
width: double.infinity,
constraints: const BoxConstraints(
maxWidth: 500,
),
decoration: BoxDecoration(
color:
AppTheme.secondaryBackground,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: AppTheme.alternate,
width: 2,
),
),
child: const Padding(
padding: EdgeInsets.all(8),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Icon(
Icons.add_a_photo_rounded,
color: AppTheme.primary,
size: 32,
),
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(16, 0, 0, 0),
child: Text(
'Upload Screenshot',
textAlign: TextAlign.center,
style: AppTheme.bodyMedium,
),
),
],
),
),
).animateOnPageLoad(
animationsMap['containerOnPageLoadAnimation3']!),
),
Padding(
padding: const EdgeInsetsDirectional.fromSTEB(0, 24, 0, 12),
child: FFButtonWidget(
onPressed: () {
print('Button pressed ...');
},
text: 'Submit Ticket',
icon: const Icon(
Icons.receipt_long,
size: 15,
),
options: FFButtonOptions(
width: double.infinity,
height: 48,
padding: const EdgeInsets.all(0),
iconPadding:
const EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
color: AppTheme.primary,
textStyle: AppTheme.titleSmall,
elevation: 4,
borderSide: const BorderSide(
color: Colors.transparent,
width: 1,
),
borderRadius: BorderRadius.circular(60),
),
),
),
],
),
),
),
),
),
),
);
}
}