Initial commit: Penyerahan final Source code Tugas Akhir

This commit is contained in:
ferdiakhh
2025-07-10 19:15:14 +07:00
commit e1f2206b8a
687 changed files with 80132 additions and 0 deletions

View File

@ -0,0 +1,198 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:initial_folder/models/announcement_model.dart';
import 'package:initial_folder/providers/announcement_provider.dart';
import 'package:initial_folder/providers/like_announcement.dart';
import 'package:initial_folder/screens/course/component/inside_announcement.dart';
import 'package:provider/provider.dart';
import '../get_it.dart';
import '../size_config.dart';
import '../theme.dart';
class AnnouncementUser extends StatefulWidget {
const AnnouncementUser({
Key? key,
required this.id,
this.divider,
required this.announcementDataModel,
required this.index,
required this.userId,
}) : super(key: key);
final Widget? divider;
final id;
final AnnouncementDataModel announcementDataModel;
final int index;
final int userId;
@override
State<AnnouncementUser> createState() => _AnnouncementUserState();
}
class _AnnouncementUserState extends State<AnnouncementUser> {
double value = 0;
final provider = announcementGetIt<AnnouncementProvider>();
@override
Widget build(BuildContext context) {
LikeOrAnnouncementProvider _likeOrAnnouncementProvider =
Provider.of<LikeOrAnnouncementProvider>(context);
likeOrAnnouncement(String tokenAnnouncement) async {
final provider = announcementGetIt<AnnouncementProvider>();
if (await _likeOrAnnouncementProvider
.likeOrAnnouncement(tokenAnnouncement)) {
provider.getAnnouncement(widget.id);
}
}
return Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => InsideAnnouncement(
announcementDataModel: widget.announcementDataModel,
id: widget.id,
index: widget.index,
userId: widget.userId,
),
),
).then((value) => provider.getAnnouncement(widget.id));
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
CircleAvatar(
backgroundColor: primaryColor,
backgroundImage:
widget.announcementDataModel.fotoProfile == null
? AssetImage("assets/images/Profile Image.png")
: NetworkImage(
widget.announcementDataModel.fotoProfile ??
'') as ImageProvider,
),
SizedBox(
width: getProportionateScreenWidth(8),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
widget.announcementDataModel.instructorName ?? '',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color:
Theme.of(context).colorScheme.onBackground,
),
),
],
),
Text(
widget.announcementDataModel.date ?? '',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color: Theme.of(context).colorScheme.onBackground,
),
),
],
),
],
),
SizedBox(height: getProportionateScreenHeight(9)),
Text(
widget.announcementDataModel.bodyContent ?? '',
style: thirdTextStyle.copyWith(
color: Theme.of(context).colorScheme.onBackground,
letterSpacing: 1,
fontSize: SizeConfig.blockHorizontal! * 3.4,
),
),
SizedBox(height: getProportionateScreenHeight(5)),
],
),
),
Row(
children: [
kLike(
widget.announcementDataModel.isLike == 1
? Icons.favorite
: Icons.favorite_border_rounded,
widget.announcementDataModel.isLike == 1
? Colors.red
: secondaryColor, () {
likeOrAnnouncement(
widget.announcementDataModel.tokenAnnouncement!);
}),
SizedBox(
width: getProportionateScreenWidth(3),
),
Text(
"${widget.announcementDataModel.countLike ?? 0}",
style: secondaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
letterSpacing: 0.3,
),
),
SizedBox(width: getProportionateScreenWidth(13)),
kComment(widget.announcementDataModel.replies.length),
],
),
SizedBox(
height: getProportionateScreenWidth(13),
),
SizedBox(
child: widget.divider,
)
],
),
);
}
}
Widget kLike(IconData icon, Color color, Function onTap) {
return GestureDetector(
onTap: () => onTap(),
child: Row(
children: [
Icon(
icon,
color: color,
size: 12,
),
],
),
);
}
Widget kComment(int value) {
return Row(
children: [
Icon(
FontAwesomeIcons.comment,
color: secondaryColor,
size: 12,
),
SizedBox(
width: getProportionateScreenWidth(3),
),
Text(
"$value",
style: secondaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10), letterSpacing: 0.3),
)
],
);
}

View File

@ -0,0 +1,124 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/models/announcement_model.dart';
import 'package:initial_folder/providers/announcement_provider.dart';
import 'package:initial_folder/widgets/announcement_user.dart';
import '../get_it.dart';
import '../theme.dart';
class AnnouncementUserPage extends StatefulWidget {
const AnnouncementUserPage({Key? key, required this.idCourse})
: super(key: key);
final idCourse;
@override
State<AnnouncementUserPage> createState() => _AnnouncementUserPageState();
}
class _AnnouncementUserPageState extends State<AnnouncementUserPage> {
final provider = announcementGetIt<AnnouncementProvider>();
int? userId = 0;
void getUserId() async {
userId = await UsersInfo().getIdUser();
}
@override
void initState() {
// TODO: implement initState
getUserId();
super.initState();
}
@override
Widget build(BuildContext context) {
provider.getAnnouncement(widget.idCourse);
late Widget build;
return StreamBuilder<AnnouncementModel>(
stream: provider.announcementStream,
builder: (context, AsyncSnapshot<AnnouncementModel> snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(
'Terjadi Kesalahan',
style: thirdTextStyle,
),
);
} else {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
build = Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
break;
case ConnectionState.none:
build = Center(
child: Text(
'Tidak ada koneksi',
style: thirdTextStyle,
),
);
break;
case ConnectionState.active:
if (snapshot.data!.data[0].isEmpty) {
build = Center(
child: Text(
'Tidak Ada Pengumuman',
style: thirdTextStyle,
),
);
} else {
build = ListView.builder(
itemCount: snapshot.data!.data[0].length,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return AnnouncementUser(
divider: Divider(),
announcementDataModel: snapshot.data!.data[0][index],
id: widget.idCourse,
index: index,
userId: userId!,
);
},
);
}
break;
case ConnectionState.done:
if (snapshot.data!.data[0].isEmpty) {
build = Center(
child: Text(
'Belum ada pengumuman',
style: thirdTextStyle,
),
);
} else {
build = ListView.builder(
itemCount: snapshot.data!.data[0].length,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return AnnouncementUser(
divider: Divider(),
announcementDataModel: snapshot.data!.data[0][index],
id: widget.idCourse,
index: index,
userId: userId!,
);
},
);
}
break;
}
}
return build;
},
);
}
}

View File

@ -0,0 +1,20 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/models/counter_qna_comment_model.dart';
import '../size_config.dart';
import '../theme.dart';
class CounterQnaComment extends StatelessWidget {
const CounterQnaComment({Key? key, required this.counterComment})
: super(key: key);
final String counterComment;
@override
Widget build(BuildContext context) {
return Text(
'${counterComment}',
style: secondaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10), letterSpacing: 0.3),
);
}
}

View File

@ -0,0 +1,64 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/counter_qna_comment_provider.dart';
import 'package:initial_folder/widgets/counter_qna_comment.dart';
import 'package:provider/provider.dart';
import '../theme.dart';
class CounterQnaCommentPage extends StatelessWidget {
const CounterQnaCommentPage({Key? key, required this.idQna})
: super(key: key);
final idQna;
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => CounterQnaCommentProvider(idQna: idQna),
child: Consumer<CounterQnaCommentProvider>(builder: (context, state, _) {
if (state.state == ResultState.loading) {
print(idQna);
return Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
} else if (state.state == ResultState.noData) {
return Center(
child: Text(
'TIDAK ADA',
style: thirdTextStyle,
),
);
} else if (state.state == ResultState.hasData) {
var counterQna = state.result!.data;
return CounterQnaComment(
counterComment: counterQna!,
);
// var counterQna = state.result!.data;
// return CounterQnaComment(
// counterComment: counterQna,
// );
} else if (state.state == ResultState.error) {
return Center(
child: Column(
children: [
Text(
'Terjadi Kesalahan Coba Lagi',
style: thirdTextStyle,
),
],
));
}
return Center(
child: Text(
'Terjadi Kesalahan',
style: thirdTextStyle,
),
);
}),
);
}
}

View File

@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/like_or_unlike_provider.dart';
import 'package:provider/provider.dart';
import '../size_config.dart';
import '../theme.dart';
class CounterQnaLike extends StatelessWidget {
const CounterQnaLike({
Key? key,
required this.counterLike,
}) : super(key: key);
final counterLike;
@override
Widget build(BuildContext context) {
return Text(
'${counterLike}',
style: secondaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10), letterSpacing: 0.3),
);
}
}

View File

@ -0,0 +1,63 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/counter_qna_like_provider.dart';
import 'package:initial_folder/widgets/counter_qna_like.dart';
import 'package:provider/provider.dart';
import '../theme.dart';
class CounterQnaLikePage extends StatelessWidget {
const CounterQnaLikePage({Key? key, required this.idQna}) : super(key: key);
final idQna;
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => CounterQnaLikeProvider(idQna: idQna),
child: Consumer<CounterQnaLikeProvider>(builder: (context, state, _) {
if (state.state == ResultState.loading) {
print(idQna);
return Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
} else if (state.state == ResultState.noData) {
return Center(
child: Text(
'TIDAK ADA',
style: thirdTextStyle,
),
);
} else if (state.state == ResultState.hasData) {
var counterQna = state.result!.data;
return CounterQnaLike(
counterLike: counterQna,
);
// var counterQna = state.result!.data;
// return CounterQnaComment(
// counterComment: counterQna,
// );
} else if (state.state == ResultState.error) {
return Center(
child: Column(
children: [
Text(
'Terjadi Kesalahan Coba Lagi',
style: thirdTextStyle,
),
],
));
}
return Center(
child: Text(
'Terjadi Kesalahan',
style: thirdTextStyle,
),
);
}),
);
}
}

View File

@ -0,0 +1,376 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
const Duration _kExpand = Duration(milliseconds: 200);
/// A single-line [ListTile] with an expansion arrow icon that expands or collapses
/// the tile to reveal or hide the [children].
///
/// This widget is typically used with [ListView] to create an
/// "expand / collapse" list entry. When used with scrolling widgets like
/// [ListView], a unique [PageStorageKey] must be specified to enable the
/// [CustomExpansionTile] to save and restore its expanded state when it is scrolled
/// in and out of view.
///
/// This class overrides the [ListTileThemeData.iconColor] and [ListTileThemeData.textColor]
/// theme properties for its [ListTile]. These colors animate between values when
/// the tile is expanded and collapsed: between [iconColor], [collapsedIconColor] and
/// between [textColor] and [collapsedTextColor].
///
/// The expansion arrow icon is shown on the right by default in left-to-right languages
/// (i.e. the trailing edge). This can be changed using [controlAffinity]. This maps
/// to the [leading] and [trailing] properties of [CustomExpansionTile].
///
/// {@tool dartpad}
/// This example demonstrates different configurations of CustomExpansionTile.
///
/// ** See code in examples/api/lib/material/expansion_tile/expansion_tile.0.dart **
/// {@end-tool}
///
/// See also:
///
/// * [ListTile], useful for creating expansion tile [children] when the
/// expansion tile represents a sublist.
/// * The "Expand and collapse" section of
/// <https://material.io/components/lists#types>
class CustomExpansionTile extends StatefulWidget {
/// Creates a single-line [ListTile] with an expansion arrow icon that expands or collapses
/// the tile to reveal or hide the [children]. The [initiallyExpanded] property must
/// be non-null.
const CustomExpansionTile({
Key? key,
this.leading,
required this.title,
this.subtitle,
this.onExpansionChanged,
this.children = const <Widget>[],
this.initiallyExpanded = false,
this.maintainState = false,
this.tilePadding,
this.expandedCrossAxisAlignment,
this.expandedAlignment,
this.childrenPadding,
this.backgroundColor,
this.collapsedBackgroundColor,
this.textColor,
this.collapsedTextColor,
this.iconColor,
this.collapsedIconColor,
this.controlAffinity,
}) : assert(initiallyExpanded != null),
assert(maintainState != null),
assert(
expandedCrossAxisAlignment != CrossAxisAlignment.baseline,
'CrossAxisAlignment.baseline is not supported since the expanded children '
'are aligned in a column, not a row. Try to use another constant.',
),
super(key: key);
/// A widget to display before the title.
///
/// Typically a [CircleAvatar] widget.
///
/// Note that depending on the value of [controlAffinity], the [leading] widget
/// may replace the rotating expansion arrow icon.
final Widget? leading;
/// The primary content of the list item.
///
/// Typically a [Text] widget.
final Widget title;
/// Additional content displayed below the title.
///
/// Typically a [Text] widget.
final Widget? subtitle;
/// Called when the tile expands or collapses.
///
/// When the tile starts expanding, this function is called with the value
/// true. When the tile starts collapsing, this function is called with
/// the value false.
final ValueChanged<bool>? onExpansionChanged;
/// The widgets that are displayed when the tile expands.
///
/// Typically [ListTile] widgets.
final List<Widget> children;
/// The color to display behind the sublist when expanded.
final Color? backgroundColor;
/// When not null, defines the background color of tile when the sublist is collapsed.
final Color? collapsedBackgroundColor;
/// A widget to display after the title.
///
/// Note that depending on the value of [controlAffinity], the [trailing] widget
/// may replace the rotating expansion arrow icon.
/// Specifies if the list tile is initially expanded (true) or collapsed (false, the default).
final bool initiallyExpanded;
/// Specifies whether the state of the children is maintained when the tile expands and collapses.
///
/// When true, the children are kept in the tree while the tile is collapsed.
/// When false (default), the children are removed from the tree when the tile is
/// collapsed and recreated upon expansion.
final bool maintainState;
/// Specifies padding for the [ListTile].
///
/// Analogous to [ListTile.contentPadding], this property defines the insets for
/// the [leading], [title], [subtitle] and [trailing] widgets. It does not inset
/// the expanded [children] widgets.
///
/// When the value is null, the tile's padding is `EdgeInsets.symmetric(horizontal: 16.0)`.
final EdgeInsetsGeometry? tilePadding;
/// Specifies the alignment of [children], which are arranged in a column when
/// the tile is expanded.
///
/// The internals of the expanded tile make use of a [Column] widget for
/// [children], and [Align] widget to align the column. The `expandedAlignment`
/// parameter is passed directly into the [Align].
///
/// Modifying this property controls the alignment of the column within the
/// expanded tile, not the alignment of [children] widgets within the column.
/// To align each child within [children], see [expandedCrossAxisAlignment].
///
/// The width of the column is the width of the widest child widget in [children].
///
/// When the value is null, the value of `expandedAlignment` is [Alignment.center].
final Alignment? expandedAlignment;
/// Specifies the alignment of each child within [children] when the tile is expanded.
///
/// The internals of the expanded tile make use of a [Column] widget for
/// [children], and the `crossAxisAlignment` parameter is passed directly into the [Column].
///
/// Modifying this property controls the cross axis alignment of each child
/// within its [Column]. Note that the width of the [Column] that houses
/// [children] will be the same as the widest child widget in [children]. It is
/// not necessarily the width of [Column] is equal to the width of expanded tile.
///
/// To align the [Column] along the expanded tile, use the [expandedAlignment] property
/// instead.
///
/// When the value is null, the value of `expandedCrossAxisAlignment` is [CrossAxisAlignment.center].
final CrossAxisAlignment? expandedCrossAxisAlignment;
/// Specifies padding for [children].
///
/// When the value is null, the value of `childrenPadding` is [EdgeInsets.zero].
final EdgeInsetsGeometry? childrenPadding;
/// The icon color of tile's expansion arrow icon when the sublist is expanded.
///
/// Used to override to the [ListTileThemeData.iconColor].
final Color? iconColor;
/// The icon color of tile's expansion arrow icon when the sublist is collapsed.
///
/// Used to override to the [ListTileThemeData.iconColor].
final Color? collapsedIconColor;
/// The color of the tile's titles when the sublist is expanded.
///
/// Used to override to the [ListTileThemeData.textColor].
final Color? textColor;
/// The color of the tile's titles when the sublist is collapsed.
///
/// Used to override to the [ListTileThemeData.textColor].
final Color? collapsedTextColor;
/// Typically used to force the expansion arrow icon to the tile's leading or trailing edge.
///
/// By default, the value of `controlAffinity` is [ListTileControlAffinity.platform],
/// which means that the expansion arrow icon will appear on the tile's trailing edge.
final ListTileControlAffinity? controlAffinity;
@override
State<CustomExpansionTile> createState() => _CustomExpansionTileState();
}
class _CustomExpansionTileState extends State<CustomExpansionTile>
with SingleTickerProviderStateMixin {
static final Animatable<double> _easeOutTween =
CurveTween(curve: Curves.easeOut);
static final Animatable<double> _easeInTween =
CurveTween(curve: Curves.easeIn);
static final Animatable<double> _halfTween =
Tween<double>(begin: 0.0, end: 0.5);
final ColorTween _borderColorTween = ColorTween();
final ColorTween _headerColorTween = ColorTween();
final ColorTween _iconColorTween = ColorTween();
final ColorTween _backgroundColorTween = ColorTween();
late AnimationController _controller;
late Animation<double> _iconTurns;
late Animation<double> _heightFactor;
late Animation<Color?> _borderColor;
late Animation<Color?> _headerColor;
late Animation<Color?> _iconColor;
late Animation<Color?> _backgroundColor;
bool _isExpanded = false;
@override
void initState() {
super.initState();
_controller = AnimationController(duration: _kExpand, vsync: this);
_heightFactor = _controller.drive(_easeInTween);
_iconTurns = _controller.drive(_halfTween.chain(_easeInTween));
_borderColor = _controller.drive(_borderColorTween.chain(_easeOutTween));
_headerColor = _controller.drive(_headerColorTween.chain(_easeInTween));
_iconColor = _controller.drive(_iconColorTween.chain(_easeInTween));
_backgroundColor =
_controller.drive(_backgroundColorTween.chain(_easeOutTween));
_isExpanded = PageStorage.of(context)?.readState(context) as bool? ??
widget.initiallyExpanded;
if (_isExpanded) _controller.value = 1.0;
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void _handleTap() {
setState(() {
_isExpanded = !_isExpanded;
if (_isExpanded) {
_controller.forward();
} else {
_controller.reverse().then<void>((void value) {
if (!mounted) return;
setState(() {
// Rebuild without widget.children.
});
});
}
PageStorage.of(context)?.writeState(context, _isExpanded);
});
widget.onExpansionChanged?.call(_isExpanded);
}
// Platform or null affinity defaults to trailing.
ListTileControlAffinity _effectiveAffinity(
ListTileControlAffinity? affinity) {
switch (affinity ?? ListTileControlAffinity.trailing) {
case ListTileControlAffinity.leading:
return ListTileControlAffinity.leading;
case ListTileControlAffinity.trailing:
case ListTileControlAffinity.platform:
return ListTileControlAffinity.trailing;
}
}
Widget? _buildIcon(BuildContext context) {
return RotationTransition(
turns: _iconTurns,
child: const Icon(Icons.add),
);
}
Widget? _buildLeadingIcon(BuildContext context) {
if (_effectiveAffinity(widget.controlAffinity) !=
ListTileControlAffinity.leading) return null;
return _buildIcon(context);
}
Widget? _buildTrailingIcon(BuildContext context) {
if (_effectiveAffinity(widget.controlAffinity) !=
ListTileControlAffinity.trailing) return null;
return _buildIcon(context);
}
Widget _buildChildren(BuildContext context, Widget? child) {
final Color borderSideColor = _borderColor.value ?? Colors.transparent;
return Container(
decoration: BoxDecoration(
color: _backgroundColor.value ?? Colors.transparent,
border: Border(
top: BorderSide(color: borderSideColor),
bottom: BorderSide(color: borderSideColor),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTileTheme.merge(
iconColor: _iconColor.value,
textColor: _headerColor.value,
child: ListTile(
onTap: _handleTap,
contentPadding: widget.tilePadding,
leading: widget.leading ?? _buildLeadingIcon(context),
title: widget.title,
subtitle: widget.subtitle,
trailing: _isExpanded ? Icon(Icons.remove) : Icon(Icons.add),
),
),
ClipRect(
child: Align(
alignment: widget.expandedAlignment ?? Alignment.center,
heightFactor: _heightFactor.value,
child: child,
),
),
],
),
);
}
@override
void didChangeDependencies() {
final ThemeData theme = Theme.of(context);
final ColorScheme colorScheme = theme.colorScheme;
_borderColorTween.end = theme.dividerColor;
_headerColorTween
..begin = widget.collapsedTextColor ?? theme.textTheme.subtitle1!.color
..end = widget.textColor ?? colorScheme.primary;
_iconColorTween
..begin = widget.collapsedIconColor ?? theme.unselectedWidgetColor
..end = widget.iconColor ?? colorScheme.primary;
_backgroundColorTween
..begin = widget.collapsedBackgroundColor
..end = widget.backgroundColor;
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
final bool closed = !_isExpanded && _controller.isDismissed;
final bool shouldRemoveChildren = closed && !widget.maintainState;
final Widget result = Offstage(
offstage: closed,
child: TickerMode(
enabled: !closed,
child: Padding(
padding: widget.childrenPadding ?? EdgeInsets.zero,
child: Column(
crossAxisAlignment:
widget.expandedCrossAxisAlignment ?? CrossAxisAlignment.center,
children: widget.children,
),
),
),
);
return AnimatedBuilder(
animation: _controller.view,
builder: _buildChildren,
child: shouldRemoveChildren ? null : result,
);
}
}

View File

@ -0,0 +1,22 @@
import 'package:flutter/material.dart';
class CustomNavigator extends PageRouteBuilder {
CustomNavigator({required this.child})
: super(
transitionDuration: Duration(milliseconds: 100),
pageBuilder: (context, animation, secondaryAnimation) => child,
);
final Widget child;
@override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) =>
SlideTransition(
position: Tween<Offset>(
begin: Offset(1, 0),
end: Offset.zero,
).animate(animation),
child: child,
);
}

View File

@ -0,0 +1,22 @@
import 'package:flutter/material.dart';
class CustomNavigatorBottom extends PageRouteBuilder {
CustomNavigatorBottom({required this.child})
: super(
transitionDuration: Duration(milliseconds: 100),
pageBuilder: (context, animation, secondaryAnimation) => child,
);
final Widget child;
@override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) =>
SlideTransition(
position: Tween<Offset>(
begin: Offset(0, 1),
end: Offset.zero,
).animate(animation),
child: child,
);
}

View File

@ -0,0 +1,22 @@
import 'package:flutter/material.dart';
class CustomNavigatorPop extends PageRouteBuilder {
CustomNavigatorPop({required this.child})
: super(
transitionDuration: Duration(milliseconds: 100),
pageBuilder: (context, animation, secondaryAnimation) => child,
);
final Widget child;
@override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) =>
SlideTransition(
position: Tween<Offset>(
begin: Offset(-1, 0),
end: Offset.zero,
).animate(animation),
child: child,
);
}

View File

@ -0,0 +1,282 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/main.dart';
import 'package:initial_folder/providers/posting_qna_provider.dart';
import 'package:initial_folder/providers/qna_provider.dart';
import 'package:provider/provider.dart';
import 'package:quill_html_editor/quill_html_editor.dart';
import '../size_config.dart';
import '../theme.dart';
class EditQna extends StatefulWidget {
const EditQna(
{Key? key,
required this.quest,
required this.title,
required this.id_lesson,
required this.id_qna,
required this.id_course,})
: super(key: key);
final quest;
final id_lesson;
final title;
final id_qna;
final id_course;
@override
State<EditQna> createState() => _EditQnaState();
}
class _EditQnaState extends State<EditQna> {
final TextEditingController _controllerTitle = TextEditingController();
final QuillEditorController _controllerQuest = QuillEditorController();
final customToolbar = [
ToolBarStyle.headerOne,
ToolBarStyle.headerTwo,
ToolBarStyle.bold,
ToolBarStyle.italic,
ToolBarStyle.underline,
ToolBarStyle.color,
ToolBarStyle.listBullet,
ToolBarStyle.listOrdered,
];
late String initialTitle;
late String initialQuest;
double value = 0;
@override
void initState() {
initialTitle = widget.title;
initialQuest = widget.quest;
_controllerTitle.text = widget.title;
super.initState();
}
@override
void dispose() {
_controllerTitle.dispose();
_controllerQuest.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
PostingQnaProvider editQnaProvider =
Provider.of<PostingQnaProvider>(context);
return Scaffold(
appBar: AppBar(
title: Text(
'Edit Pertanyaan',
style: primaryTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(16),
letterSpacing: 0.2,
),
),
),
body: Stack(
children: [
Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16),
),
child: Column(
children: [
SizedBox(
height: 15,
),
TextField(
controller: _controllerTitle,
cursorColor: secondaryColor,
scrollPadding: EdgeInsets.zero,
decoration: InputDecoration(
filled: true,
fillColor: Theme.of(context).brightness == Brightness.dark
? seventeenColor
: Colors.grey[200],
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
),
hintStyle: secondaryTextStyle.copyWith(
color: secondaryColor,
letterSpacing: 0.5,
fontSize: getProportionateScreenWidth(12),
),
hintText: "Masukkan Judul Pertanyaan",
),
),
SizedBox(height: getProportionateScreenWidth(18)),
ToolBar(
toolBarColor: Theme.of(context).brightness == Brightness.dark
? seventeenColor
: Colors.grey[200]!,
activeIconColor: primaryColor,
iconColor: secondaryColor,
padding: const EdgeInsets.all(8),
iconSize: 20,
controller: _controllerQuest,
toolBarConfig: customToolbar,
),
Container(
height: 180,
width: double.infinity,
padding: EdgeInsets.all(15),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
),
color: Theme.of(context).colorScheme.primaryContainer,
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 0.5,
offset: Offset(0, 2),
spreadRadius: 0.001,
),
],
),
child: QuillHtmlEditor(
hintText: 'Edit pertanyaan Anda',
controller: _controllerQuest,
isEnabled: true,
minHeight: 100,
backgroundColor:
Theme.of(context).brightness == Brightness.dark
? seventeenColor
: Colors.grey[200]!,
textStyle: secondaryTextStyle.copyWith(
// color: secondaryColor,
fontSize: getProportionateScreenWidth(16),
),
hintTextStyle: secondaryTextStyle.copyWith(
// color: secondaryColor,
fontSize: getProportionateScreenWidth(16),
),
hintTextAlign: TextAlign.start,
padding: const EdgeInsets.all(3),
hintTextPadding: const EdgeInsets.all(0),
loadingBuilder: (context) {
return const Center(
child: CircularProgressIndicator(
strokeWidth: 0.4,
),
);
},
onEditorCreated: () {
if (widget.quest.isNotEmpty) {
_controllerQuest.setText(widget.quest);
}
},
),
),
SizedBox(height: getProportionateScreenHeight(4)),
Align(
alignment: Alignment.topRight,
child: ElevatedButton(
onPressed: () async {
String currentTitle = _controllerTitle.text;
String currentQuest = await _controllerQuest.getText();
String currentQuestTrimmed = currentQuest.trim();
String initialQuestTrimmed = initialQuest.trim();
// Cek apakah ada perubahan
if (currentTitle == initialTitle &&
currentQuestTrimmed == initialQuestTrimmed) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: primaryColor,
content: Text(
'Tidak ada perubahan',
style: primaryTextStyle.copyWith(
color: Colors.white,
),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
);
} else {
bool success = await editQnaProvider.editQna(
widget.id_course,
currentQuest,
int.parse(widget.id_qna.toString()),
currentTitle,
widget.id_lesson,
);
if (success) {
ScaffoldMessenger.of(globalScaffoldKey.currentContext!)
.showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: primaryColor,
content: Text(
'Pertanyaan berhasil diedit',
style: primaryTextStyle.copyWith(
color:Colors.white,
),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
);
_controllerQuest.clear();
_controllerTitle.clear();
Navigator.pop(context);
} else {
ScaffoldMessenger.of(globalScaffoldKey.currentContext!)
.showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: primaryColor,
content: Text(
'Terjadi kesalahan',
style: primaryTextStyle.copyWith(
color: Colors.white,
),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
);
}
}
},
child: Text(
'Edit Pertanyaan',
style: thirdTextStyle.copyWith(
color: Colors.white,
fontSize: SizeConfig.blockHorizontal! * 4,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: primaryColor,
),
),
),
],
),
)
],
),
);
}
}

View File

@ -0,0 +1,171 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/posting_qna_reply_provider.dart';
import 'package:initial_folder/screens/course/component/detail_quest_and_answer.dart';
import 'package:provider/provider.dart';
import '../size_config.dart';
import '../theme.dart';
class EditReplyQna extends StatefulWidget {
const EditReplyQna(
{Key? key,
required this.id_qna,
required this.text_rep,
required this.id_rep})
: super(key: key);
final id_qna;
final text_rep;
final id_rep;
@override
State<EditReplyQna> createState() => _EditReplyQnaState();
}
class _EditReplyQnaState extends State<EditReplyQna> {
final _textControlBalasan = TextEditingController();
double value = 0;
@override
void initState() {
if (widget.text_rep != null) {
_textControlBalasan.text = widget.text_rep ?? '';
}
super.initState();
}
@override
void dispose() {
_textControlBalasan.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
PostingQnaReplyProvider editQnaReplyProvider =
Provider.of<PostingQnaReplyProvider>(context);
return Scaffold(
appBar: AppBar(
title: Text(
'Edit Balasan',
style: primaryTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(16),
letterSpacing: 0.2,
),
),
),
body: Stack(
children: [
Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16),
),
child: Column(
children: [
SizedBox(
height: 15,
),
TextField(
controller: _textControlBalasan,
cursorColor: secondaryColor,
scrollPadding: EdgeInsets.zero,
minLines: 2,
keyboardType: TextInputType.multiline,
maxLines: null,
decoration: InputDecoration(
filled: true,
fillColor: Theme.of(context).brightness == Brightness.dark
? seventeenColor
: Colors.grey[200],
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(
10,
),
borderSide: BorderSide.none),
hintStyle: secondaryTextStyle.copyWith(
color: secondaryColor,
letterSpacing: 0.5,
fontSize: getProportionateScreenWidth(12),
),
),
),
SizedBox(
height: getProportionateScreenHeight(4),
),
Align(
alignment: Alignment.topRight,
child: ElevatedButton(
onPressed: () async {
if (await editQnaReplyProvider
.editQnaReply(
_textControlBalasan.text,
int.parse(widget.id_rep.toString()),
widget.id_qna)
.whenComplete(
() {
_textControlBalasan.clear();
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: primaryColor,
content: Text(
'Balasan berhasil diedit',
style: primaryTextStyle.copyWith(
color: Colors.white,
),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
);
return Navigator.pop(context, true);
// await Provider.of(context)<QnaProvider>(context,
// listen: true)
// .getQna(widget.id_course);
},
))
;
else {
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: primaryColor,
content: Text(
'Terjadi kesalahan',
style: primaryTextStyle.copyWith(
color: backgroundColor,
),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
);
}
},
child: Text(
'Edit Balasan',
style: thirdTextStyle.copyWith(
color: Colors.white,
fontSize: SizeConfig.blockHorizontal! * 4,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: primaryColor,
),
),
),
],
),
)
],
),
);
}
}

View File

@ -0,0 +1,10 @@
import 'package:flutter/material.dart';
class ListNotifikasi extends StatelessWidget {
const ListNotifikasi({Key? key, required this.data}) : super(key: key);
final List data;
@override
Widget build(BuildContext context) {
return Text(data[0].toString());
}
}

View File

@ -0,0 +1,136 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
class LoadingMyCourse extends StatelessWidget {
const LoadingMyCourse({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
children: [
Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(16),
right: getProportionateScreenWidth(16),
top: getProportionateScreenWidth(10),
),
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Flexible(
flex: 11,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(156),
height: getProportionateScreenWidth(88),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: secondaryColor),
),
SizedBox(
height: getProportionateScreenHeight(8),
),
],
)),
SizedBox(
width: getProportionateScreenWidth(9),
),
Flexible(
flex: 10,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 30,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: secondaryColor),
),
SizedBox(
height: getProportionateScreenWidth(8),
),
Container(
height: 8,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: secondaryColor),
),
SizedBox(
height: getProportionateScreenWidth(6),
),
Row(
children: [
Container(
height: 10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: secondaryColor),
),
SizedBox(
width: getProportionateScreenWidth(5),
),
Container(
height: 10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: secondaryColor),
),
],
),
],
),
),
],
),
Container(
height: getProportionateScreenWidth(4),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: secondaryColor),
),
SizedBox(height: getProportionateScreenWidth(6)),
Align(
alignment: Alignment.topLeft,
child: Container(
width: 30,
height: 10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: secondaryColor),
),
),
Row(children: [
Container(
height: 20,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: secondaryColor),
),
SizedBox(
width: getProportionateScreenWidth(10),
),
Container(
height: 20,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: secondaryColor),
),
]),
],
),
),
Divider(
color: fourthColor,
),
],
);
}
}

View File

@ -0,0 +1,978 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
IconData fontAwesomeIconsFromString(String name) {
switch (name) {
case "FontAwesomeIcons.moneyBillAlt":
return FontAwesomeIcons.moneyBillAlt;
case "FontAwesomeIcons.desktop":
return FontAwesomeIcons.desktop;
case "FontAwesomeIcons.music":
return FontAwesomeIcons.music;
case "FontAwesomeIcons.pencilAlt":
return FontAwesomeIcons.pencilAlt;
case "FontAwesomeIcons.pencilRuler":
return FontAwesomeIcons.pencilRuler;
case "FontAwesomeIcons.shoppingBag":
return FontAwesomeIcons.shoppingBag;
case "FontAwesomeIcons.chartLine":
return FontAwesomeIcons.chartLine;
case "FontAwesomeIcons.clipboardList":
return FontAwesomeIcons.clipboardList;
case "FontAwesomeIcons.chess":
return FontAwesomeIcons.chess;
case "FontAwesomeIcons.cameraRetro":
return FontAwesomeIcons.cameraRetro;
case "FontAwesomeIcons.graduationCap":
return FontAwesomeIcons.graduationCap;
case "FontAwesomeIcons.accessibleIcon":
return FontAwesomeIcons.accessibleIcon;
case "FontawesomeIcons.accusoft":
return FontAwesomeIcons.accusoft;
case "FontAwesomeIcons.acquisitionIncorporated":
return FontAwesomeIcons.a;
case "FontAwesomeIcons.ad":
return FontAwesomeIcons.ad;
case "FontAwesomeIcons.addressBook":
return FontAwesomeIcons.addressBook;
case "FontAwesomeIcons.addressCard":
return FontAwesomeIcons.addressCard;
case "FontAwesomeIcons.adjust":
return FontAwesomeIcons.adjust;
case "FontAwesomeIcons.adn":
return FontAwesomeIcons.adn;
case "FontAwesomeIcons.adversal":
return FontAwesomeIcons.adversal;
case "FontAwesomeIcons.affiliatetheme":
return FontAwesomeIcons.affiliatetheme;
case "FontAwesomeIcons.airFreshener":
return FontAwesomeIcons.airFreshener;
case "FontAwesomeIcons.airbnb":
return FontAwesomeIcons.airbnb;
case "FontAwesomeIcons.algolia":
return FontAwesomeIcons.algolia;
case "FontAwesomeIcons.alignCenter":
return FontAwesomeIcons.alignCenter;
case "FontAwesomeIcons.alignJustify":
return FontAwesomeIcons.alignJustify;
case "FontAwesomeIcons.alignLeft":
return FontAwesomeIcons.alignLeft;
case "FontAwesomeIcons.alignRight":
return FontAwesomeIcons.alignRight;
case "FontAwesomeIcons.alipay":
return FontAwesomeIcons.alipay;
case "FontAwesomeIcons.allergies":
return FontAwesomeIcons.allergies;
case "FontAwesomeIcons.amazon":
return FontAwesomeIcons.amazon;
case "FontAwesomeIcons.amazonPay":
return FontAwesomeIcons.amazonPay;
case "FontAwesomeIcons.ambulance":
return FontAwesomeIcons.ambulance;
case "FontAwesomeIcons.americanSignLanguageInterpreting":
return FontAwesomeIcons.americanSignLanguageInterpreting;
case "FontAwesomeIcons.amilia":
return FontAwesomeIcons.amilia;
case "FontAwesomeIcons.anchor":
return FontAwesomeIcons.anchor;
case "FontAwesomeIcons.android":
return FontAwesomeIcons.android;
case "FontAwesomeIcons.angellist":
return FontAwesomeIcons.angellist;
case "FontAwesomeIcons.angleDoubleDown":
return FontAwesomeIcons.angleDoubleDown;
case "FontAwesomeIcons.angleDoubleLeft":
return FontAwesomeIcons.angleDoubleLeft;
case "FontAwesomeIcons.angleDoubleRight":
return FontAwesomeIcons.angleDoubleRight;
case "FontAwesomeIcons.angleDoubleUp":
return FontAwesomeIcons.angleDoubleUp;
case "FontAwesomeIcons.angleDown":
return FontAwesomeIcons.angleDown;
case "FontAwesomeIcons.angleLeft":
return FontAwesomeIcons.angleLeft;
case "FontAwesomeIcons.angleRight":
return FontAwesomeIcons.angleRight;
case "FontAwesomeIcons.angleUp":
return FontAwesomeIcons.angleUp;
case "FontAwesomeIcons.angry":
return FontAwesomeIcons.angry;
case "FontAwesomeIcons.angrycreative":
return FontAwesomeIcons.angrycreative;
case "FontAwesomeIcons.angular":
return FontAwesomeIcons.angular;
case "FontAwesomeIcons.ankh":
return FontAwesomeIcons.ankh;
case "FontAwesomeIcons.appStore":
return FontAwesomeIcons.appStore;
case "FontAwesomeIcons.appStoreIos":
return FontAwesomeIcons.appStoreIos;
case "FontAwesomeIcons.apper":
return FontAwesomeIcons.apper;
case "FontAwesomeIcons.apple":
return FontAwesomeIcons.apple;
case "FontAwesomeIcons.appleAlt":
return FontAwesomeIcons.appleAlt;
case "FontAwesomeIcons.applePay":
return FontAwesomeIcons.applePay;
case "FontAwesomeIcons.archive":
return FontAwesomeIcons.archive;
case "FontAwesomeIcons.archway":
return FontAwesomeIcons.archway;
case "FontAwesomeIcons.arrowAltCircleDown":
return FontAwesomeIcons.arrowAltCircleDown;
case "FontAwesomeIcons.arrowAltCircleLeft":
return FontAwesomeIcons.arrowAltCircleLeft;
case "FontAwesomeIcons.arrowAltCircleRight":
return FontAwesomeIcons.arrowAltCircleRight;
case "FontAwesomeIcons.arrowAltCircleUp":
return FontAwesomeIcons.arrowAltCircleUp;
case "FontAwesomeIcons.arrowCircleDown":
return FontAwesomeIcons.arrowCircleDown;
case "FontAwesomeIcons.arrowCircleLeft":
return FontAwesomeIcons.arrowCircleLeft;
case "FontAwesomeIcons.arrowCircleRight":
return FontAwesomeIcons.arrowCircleRight;
case "FontAwesomeIcons.arrowCircleUp":
return FontAwesomeIcons.arrowCircleUp;
case "FontAwesomeIcons.arrowDown":
return FontAwesomeIcons.arrowDown;
case "FontAwesomeIcons.arrowLeft":
return FontAwesomeIcons.arrowLeft;
case "FontAwesomeIcons.arrowRight":
return FontAwesomeIcons.arrowRight;
case "FontAwesomeIcons.arrowUp":
return FontAwesomeIcons.arrowUp;
case "FontAwesomeIcons.arrowsAlt":
return FontAwesomeIcons.arrowsAlt;
case "FontAwesomeIcons.arrowsAltH":
return FontAwesomeIcons.arrowsAltH;
case "FontAwesomeIcons.arrowsAltV":
return FontAwesomeIcons.arrowsAltV;
case "FontAwesomeIcons.artstation":
return FontAwesomeIcons.artstation;
case "FontAwesomeIcons.assistiveListeningSystems":
return FontAwesomeIcons.assistiveListeningSystems;
case "FontAwesomeIcons.asterisk":
return FontAwesomeIcons.asterisk;
case "FontAwesomeIcons.asymmetrik":
return FontAwesomeIcons.asymmetrik;
case "FontAwesomeIcons.at":
return FontAwesomeIcons.at;
case "FontAwesomeIcons.atlas":
return FontAwesomeIcons.atlas;
case "FontAwesomeIcons.atlassian":
return FontAwesomeIcons.atlassian;
case "FontAwesomeIcons.atom":
return FontAwesomeIcons.atom;
case "FontAwesomeIcons.audible":
return FontAwesomeIcons.audible;
case "FontAwesomeIcons.audioDescription":
return FontAwesomeIcons.audioDescription;
case "FontAwesomeIcons.autoprefixer":
return FontAwesomeIcons.autoprefixer;
case "FontAwesomeIcons.avianex":
return FontAwesomeIcons.avianex;
case "FontAwesomeIcons.aviato":
return FontAwesomeIcons.aviato;
case "FontAwesomeIcons.award":
return FontAwesomeIcons.award;
case "FontAwesomeIcons.aws":
return FontAwesomeIcons.aws;
case "FontAwesomeIcons.baby":
return FontAwesomeIcons.baby;
case "FontAwesomeIcons.babyCarriage":
return FontAwesomeIcons.babyCarriage;
case "FontAwesomeIcons.backspace":
return FontAwesomeIcons.backspace;
case "FontAwesomeIcons.backward":
return FontAwesomeIcons.backward;
case "FontAwesomeIcons.bacon":
return FontAwesomeIcons.bacon;
case "FontAwesomeIcons.bahai":
return FontAwesomeIcons.bahai;
case "FontAwesomeIcons.balanceScale":
return FontAwesomeIcons.balanceScale;
case "FontAwesomeIcons.balanceScaleLeft":
return FontAwesomeIcons.balanceScaleLeft;
case "FontAwesomeIcons.balanceScaleRight":
return FontAwesomeIcons.balanceScaleRight;
case "FontAwesomeIcons.ban":
return FontAwesomeIcons.ban;
case "FontAwesomeIcons.bandAid":
return FontAwesomeIcons.bandAid;
case "FontAwesomeIcons.bandcamp":
return FontAwesomeIcons.bandcamp;
case "FontAwesomeIcons.barcode":
return FontAwesomeIcons.barcode;
case "FontAwesomeIcons.bars":
return FontAwesomeIcons.bars;
case "FontAwesomeIcons.baseballBall":
return FontAwesomeIcons.baseballBall;
case "FontAwesomeIcons.basketballBall":
return FontAwesomeIcons.basketballBall;
case "FontAwesomeIcons.bath":
return FontAwesomeIcons.bath;
case "FontAwesomeIcons.batteryEmpty":
return FontAwesomeIcons.batteryEmpty;
case "FontAwesomeIcons.batteryFull":
return FontAwesomeIcons.batteryFull;
case "FontAwesomeIcons.batteryHalf":
return FontAwesomeIcons.batteryHalf;
case "FontAwesomeIcons.batteryQuarter":
return FontAwesomeIcons.batteryQuarter;
case "FontAwesomeIcons.batteryThreeQuarters":
return FontAwesomeIcons.batteryThreeQuarters;
case "FontAwesomeIcons.battleNet":
return FontAwesomeIcons.battleNet;
case "FontAwesomeIcons.bed":
return FontAwesomeIcons.bed;
case 'FontAwesomeIcons.beer':
return FontAwesomeIcons.beer;
case "FontAwesomeIcons.behance":
return FontAwesomeIcons.behance;
case "FontAwesomeIcons.behanceSquare":
return FontAwesomeIcons.behanceSquare;
case "FontAwesomeIcons.bell":
return FontAwesomeIcons.bell;
case "FontAwesomeIcons.bellSlash":
return FontAwesomeIcons.bellSlash;
case "FontAwesomeIcons.bezierCurve":
return FontAwesomeIcons.bezierCurve;
case "FontAwesomeIcons.bible":
return FontAwesomeIcons.bible;
case "FontAwesomeIcons.bicycle":
return FontAwesomeIcons.bicycle;
case "FontAwesomeIcons.biking":
return FontAwesomeIcons.biking;
case "FontAwesomeIcons.bimobject":
return FontAwesomeIcons.bimobject;
case "FontAwesomeIcons.binoculars":
return FontAwesomeIcons.binoculars;
case "FontAwesomeIcons.biohazard":
return FontAwesomeIcons.biohazard;
case "FontAwesomeIcons.birthdayCake":
return FontAwesomeIcons.birthdayCake;
case "FontAwesomeIcons.bitbucket":
return FontAwesomeIcons.bitbucket;
case "FontAwesomeIcons.bitcoin":
return FontAwesomeIcons.bitcoin;
case "FontAwesomeIcons.bity":
return FontAwesomeIcons.bity;
case "FontAwesomeIcons.blackTie":
return FontAwesomeIcons.blackTie;
case "FontAwesomeIcons.blackberry":
return FontAwesomeIcons.blackberry;
case "FontAwesomeIcons.blender":
return FontAwesomeIcons.blender;
case "FontAwesomeIcons.blenderPhone":
return FontAwesomeIcons.blenderPhone;
case "FontAwesomeIcons.blind":
return FontAwesomeIcons.blind;
case "FontAwesomeIcons.blog":
return FontAwesomeIcons.blog;
case "FontAwesomeIcons.blogger":
return FontAwesomeIcons.blogger;
case "FontAwesomeIcons.bloggerB":
return FontAwesomeIcons.bloggerB;
case "FontAwesomeIcons.bluetooth":
return FontAwesomeIcons.bluetooth;
case "FontAwesomeIcons.bluetoothB":
return FontAwesomeIcons.bluetoothB;
case "FontAwesomeIcons.bold":
return FontAwesomeIcons.bold;
case "FontAwesomeIcons.bolt":
return FontAwesomeIcons.bolt;
case "FontAwesomeIcons.bomb":
return FontAwesomeIcons.bomb;
case "FontAwesomeIcons.bone":
return FontAwesomeIcons.bone;
case "FontAwesomeIcons.bong":
return FontAwesomeIcons.bong;
case "FontAwesomeIcons.book":
return FontAwesomeIcons.book;
case "FontAwesomeIcons.bookDead":
return FontAwesomeIcons.bookDead;
case "FontAwesomeIcons.bookMedical":
return FontAwesomeIcons.bookMedical;
case "FontAwesomeIcons.bookOpen":
return FontAwesomeIcons.bookOpen;
case "FontAwesomeIcons.bookReader":
return FontAwesomeIcons.bookReader;
case "FontAwesomeIcons.bookmark":
return FontAwesomeIcons.bookmark;
case "FontAwesomeIcons.bootstrap":
return FontAwesomeIcons.bootstrap;
case "FontAwesomeIcons.borderAll":
return FontAwesomeIcons.borderAll;
case "FontAwesomeIcons.borderNone":
return FontAwesomeIcons.borderNone;
case "FontAwesomeIcons.borderStyle":
return FontAwesomeIcons.borderStyle;
case "FontAwesomeIcons.bowlingBall":
return FontAwesomeIcons.bowlingBall;
case "FontAwesomeIcons.box":
return FontAwesomeIcons.box;
case "FontAwesomeIcons.boxOpen":
return FontAwesomeIcons.boxOpen;
case "FontAwesomeIcons.boxTissue":
return FontAwesomeIcons.boxTissue;
case "FontAwesomeIcons.boxes":
return FontAwesomeIcons.boxes;
case "FontAwesomeIcons.braille":
return FontAwesomeIcons.braille;
case "FontAwesomeIcons.brain":
return FontAwesomeIcons.brain;
case "FontAwesomeIcons.breadSlice":
return FontAwesomeIcons.breadSlice;
case "FontAwesomeIcons.briefcase":
return FontAwesomeIcons.briefcase;
case "FontAwesomeIcons.briefcaseMedical":
return FontAwesomeIcons.briefcaseMedical;
case "FontAwesomeIcons.broadcastTower":
return FontAwesomeIcons.broadcastTower;
case "FontAwesomeIcons.broom":
return FontAwesomeIcons.broom;
case "FontAwesomeIcons.brush":
return FontAwesomeIcons.brush;
case "FontAwesomeIcons.btc":
return FontAwesomeIcons.btc;
case "FontAwesomeIcons.buffer":
return FontAwesomeIcons.buffer;
case "FontAwesomeIcons.bug":
return FontAwesomeIcons.bug;
case "FontAwesomeIcons.building":
return FontAwesomeIcons.building;
case "FontAwesomeIcons.bullhorn":
return FontAwesomeIcons.bullhorn;
case "FontAwesomeIcons.bullseye":
return FontAwesomeIcons.bullseye;
case "FontAwesomeIcons.burn":
return FontAwesomeIcons.burn;
case "FontAwesomeIcons.buromobelexperte":
return FontAwesomeIcons.buromobelexperte;
case "FontAwesomeIcons.bus":
return FontAwesomeIcons.bus;
case "FontAwesomeIcons.busAlt":
return FontAwesomeIcons.busAlt;
case "FontAwesomeIcons.businessTime":
return FontAwesomeIcons.businessTime;
case "FontAwesomeIcons.buyNLarge":
return FontAwesomeIcons.buyNLarge;
case "FontAwesomeIcons.buysellads":
return FontAwesomeIcons.buysellads;
case "FontAwesomeIcons.calculator":
return FontAwesomeIcons.calculator;
case "FontAwesomeIcons.calendar":
return FontAwesomeIcons.calendar;
case "FontAwesomeIcons.calendarAlt":
return FontAwesomeIcons.calendarAlt;
case "FontAwesomeIcons.calendarCheck":
return FontAwesomeIcons.calendarCheck;
case "FontAwesomeIcons.calendarDay":
return FontAwesomeIcons.calendarDay;
case "FontAwesomeIcons.calendarMinus":
return FontAwesomeIcons.calendarMinus;
case "FontAwesomeIcons.calendarPlus":
return FontAwesomeIcons.calendarPlus;
case "FontAwesomeIcons.calendarTimes":
return FontAwesomeIcons.calendarTimes;
case "FontAwesomeIcons.calendarWeek":
return FontAwesomeIcons.calendarWeek;
case "FontAwesomeIcons.camera":
return FontAwesomeIcons.camera;
case "FontAwesomeIcons.campground":
return FontAwesomeIcons.campground;
case "FontAwesomeIcons.canadianMapleLeaf":
return FontAwesomeIcons.canadianMapleLeaf;
case "FontAwesomeIcons.candyCane":
return FontAwesomeIcons.candyCane;
case "FontAwesomeIcons.cannabis":
return FontAwesomeIcons.cannabis;
case "FontAwesomeIcons.capsules":
return FontAwesomeIcons.capsules;
case "FontAwesomeIcons.car":
return FontAwesomeIcons.car;
case "FontAwesomeIcons.carAlt":
return FontAwesomeIcons.carAlt;
case "FontAwesomeIcons.carBattery":
return FontAwesomeIcons.carBattery;
case "FontAwesomeIcons.carCrash":
return FontAwesomeIcons.carCrash;
case "FontAwesomeIcons.carSide":
return FontAwesomeIcons.carSide;
case "FontAwesomeIcons.caravan":
return FontAwesomeIcons.caravan;
case "FontAwesomeIcons.caretDown":
return FontAwesomeIcons.caretDown;
case "FontAwesomeIcons.caretLeft":
return FontAwesomeIcons.caretLeft;
case "FontAwesomeIcons.caretRight":
return FontAwesomeIcons.caretRight;
case "FontAwesomeIcons.caretSquareDown":
return FontAwesomeIcons.caretSquareDown;
case "FontAwesomeIcons.caretSquareLeft":
return FontAwesomeIcons.caretSquareLeft;
case "FontAwesomeIcons.caretSquareRight":
return FontAwesomeIcons.caretSquareRight;
case "FontAwesomeIcons.caretSquareUp":
return FontAwesomeIcons.caretSquareUp;
case "FontAwesomeIcons.caretUp":
return FontAwesomeIcons.caretUp;
case "FontAwesomeIcons.carrot":
return FontAwesomeIcons.carrot;
case "FontAwesomeIcons.cartArrowDown":
return FontAwesomeIcons.cartArrowDown;
case "FontAwesomeIcons.cartPlus":
return FontAwesomeIcons.cartPlus;
case "FontAwesomeIcons.cashRegister":
return FontAwesomeIcons.cashRegister;
case "FontAwesomeIcons.cat":
return FontAwesomeIcons.cat;
case "FontAwesomeIcons.ccAmazonPay":
return FontAwesomeIcons.ccAmazonPay;
case "FontAwesomeIcons.ccAmex":
return FontAwesomeIcons.ccAmex;
case "FontAwesomeIcons.ccApplePay":
return FontAwesomeIcons.ccApplePay;
case "FontAwesomeIcons.ccDinersClub":
return FontAwesomeIcons.ccDinersClub;
case "FontAwesomeIcons.ccDiscover":
return FontAwesomeIcons.ccDiscover;
case "FontAwesomeIcons.ccJcb":
return FontAwesomeIcons.ccJcb;
case "FontAwesomeIcons.ccMastercard":
return FontAwesomeIcons.ccMastercard;
case "FontAwesomeIcons.ccPaypal":
return FontAwesomeIcons.ccPaypal;
case "FontAwesomeIcons.ccStripe":
return FontAwesomeIcons.ccStripe;
case "FontAwesomeIcons.ccVisa":
return FontAwesomeIcons.ccVisa;
case "FontAwesomeIcons.centercode":
return FontAwesomeIcons.centercode;
case "FontAwesomeIcons.centos":
return FontAwesomeIcons.centos;
case "FontAwesomeIcons.certificate":
return FontAwesomeIcons.certificate;
case "FontAwesomeIcons.chair":
return FontAwesomeIcons.chair;
case "FontAwesomeIcons.chalkboard":
return FontAwesomeIcons.chalkboard;
case "FontAwesomeIcons.chalkboardTeacher":
return FontAwesomeIcons.chalkboardTeacher;
case "FontAwesomeIcons.chargingStation":
return FontAwesomeIcons.chargingStation;
case "FontAwesomeIcons.chartArea":
return FontAwesomeIcons.chartArea;
case "FontAwesomeIcons.chartBar":
return FontAwesomeIcons.chartBar;
case "FontAwesomeIcons.chartLine":
return FontAwesomeIcons.chartLine;
case "FontAwesomeIcons.chartPie":
return FontAwesomeIcons.chartPie;
case "FontAwesomeIcons.check":
return FontAwesomeIcons.check;
case "FontAwesomeIcons.checkCircle":
return FontAwesomeIcons.checkCircle;
case "FontAwesomeIcons.checkDouble":
return FontAwesomeIcons.checkDouble;
case "FontAwesomeIcons.checkSquare":
return FontAwesomeIcons.checkSquare;
case "FontAwesomeIcons.cheese":
return FontAwesomeIcons.cheese;
case "FontAwesomeIcons.chessBishop":
return FontAwesomeIcons.chessBishop;
case "FontAwesomeIcons.chessBoard":
return FontAwesomeIcons.chessBoard;
case "FontAwesomeIcons.chessKing":
return FontAwesomeIcons.chessKing;
case "FontAwesomeIcons.chessKnight":
return FontAwesomeIcons.chessKnight;
case "FontAwesomeIcons.chessPawn":
return FontAwesomeIcons.chessPawn;
case "FontAwesomeIcons.chessQueen":
return FontAwesomeIcons.chessQueen;
case "FontAwesomeIcons.chessRook":
return FontAwesomeIcons.chessRook;
case "FontAwesomeIcons.chevronCircleDown":
return FontAwesomeIcons.chevronCircleDown;
case "FontAwesomeIcons.chevronCircleLeft":
return FontAwesomeIcons.chevronCircleLeft;
case "FontAwesomeIcons.chevronCircleRight":
return FontAwesomeIcons.chevronCircleRight;
case "FontAwesomeIcons.chevronCircleUp":
return FontAwesomeIcons.chevronCircleUp;
case "FontAwesomeIcons.chevronDown":
return FontAwesomeIcons.chevronDown;
case "FontAwesomeIcons.chevronLeft":
return FontAwesomeIcons.chevronLeft;
case "FontAwesomeIcons.chevronRight":
return FontAwesomeIcons.chevronRight;
case "FontAwesomeIcons.chevronUp":
return FontAwesomeIcons.chevronUp;
case "FontAwesomeIcons.child":
return FontAwesomeIcons.child;
case "FontAwesomeIcons.chrome":
return FontAwesomeIcons.chrome;
case "FontAwesomeIcons.chromecast":
return FontAwesomeIcons.chromecast;
case "FontAwesomeIcons.church":
return FontAwesomeIcons.church;
case "FontAwesomeIcons.circle":
return FontAwesomeIcons.circle;
case "FontAwesomeIcons.circleNotch":
return FontAwesomeIcons.circleNotch;
case "FontAwesomeIcons.city":
return FontAwesomeIcons.city;
case "FontAwesomeIcons.clinicMedical":
return FontAwesomeIcons.clinicMedical;
case "FontAwesomeIcons.clipboard":
return FontAwesomeIcons.clipboard;
case "FontAwesomeIcons.clipboardCheck":
return FontAwesomeIcons.clipboardCheck;
case "FontAwesomeIcons.clipboardList":
return FontAwesomeIcons.clipboardList;
case "FontAwesomeIcons.clock":
return FontAwesomeIcons.clock;
case "FontAwesomeIcons.clone":
return FontAwesomeIcons.clone;
case "FontAwesomeIcons.closedCaptioning":
return FontAwesomeIcons.closedCaptioning;
case "FontAwesomeIcons.cloud":
return FontAwesomeIcons.cloud;
case "FontAwesomeIcons.cloudDownloadAlt":
return FontAwesomeIcons.cloudDownloadAlt;
case "FontAwesomeIcons.cloudMeatball":
return FontAwesomeIcons.cloudMeatball;
case "FontAwesomeIcons.cloudMoon":
return FontAwesomeIcons.cloudMoon;
case "FontAwesomeIcons.cloudMoonRain":
return FontAwesomeIcons.cloudMoonRain;
case "FontAwesomeIcons.cloudRains":
return FontAwesomeIcons.cloudRain;
case "FontAwesomeIcons.cloudShowersHeavy":
return FontAwesomeIcons.cloudShowersHeavy;
case "FontAwesomeIcons.cloudSun":
return FontAwesomeIcons.cloudSun;
case "FontAwesomeIcons.cloudSunRain":
return FontAwesomeIcons.cloudSunRain;
case "FontAwesomeIcons.cloudUploadAlt":
return FontAwesomeIcons.cloudUploadAlt;
case "FontAwesomeIcons.cloudscale":
return FontAwesomeIcons.cloudscale;
case "FontAwesomeIcons.cloudsmith":
return FontAwesomeIcons.cloudsmith;
case "FontAwesomeIcons.cloudversify":
return FontAwesomeIcons.cloudversify;
case "FontAwesomeIcons.cocktail":
return FontAwesomeIcons.cocktail;
case "FontAwesomeIcons.code":
return FontAwesomeIcons.code;
case "FontAwesomeIcons.codeBranch":
return FontAwesomeIcons.codeBranch;
case "FontAwesomeIcons.codepen":
return FontAwesomeIcons.codepen;
case "FontAwesomeIcons.codiepie":
return FontAwesomeIcons.codiepie;
case "FontAwesomeIcons.coffee":
return FontAwesomeIcons.coffee;
case "FontAwesomeIcons.cog":
return FontAwesomeIcons.cog;
case "FontAwesomeIcons.cogs":
return FontAwesomeIcons.cogs;
case "FontAwesomeIcons.coins":
return FontAwesomeIcons.coins;
case "FontAwesomeIcons.columns":
return FontAwesomeIcons.columns;
case "FontAwesomeIcons.comment":
return FontAwesomeIcons.comment;
case "FontAwesomeIcons.commentAlt":
return FontAwesomeIcons.commentAlt;
case "FontAwesomeIcons.commentDollar":
return FontAwesomeIcons.commentDollar;
case "FontAwesomeIcons.commentDots":
return FontAwesomeIcons.commentDots;
case "FontAwesomeIcons.commentMedical":
return FontAwesomeIcons.commentMedical;
case "FontAwesomeIcons.commentSlash":
return FontAwesomeIcons.commentSlash;
case "FontAwesomeIcons.comments":
return FontAwesomeIcons.comments;
case "FontAwesomeIcons.commentsDollar":
return FontAwesomeIcons.commentsDollar;
case "FontAwesomeIcons.compactDisc":
return FontAwesomeIcons.compactDisc;
case "FontAwesomeIcons.compass":
return FontAwesomeIcons.compass;
case "FontAwesomeIcons.compress":
return FontAwesomeIcons.compress;
case "FontAwesomeIcons.compressAlt":
return FontAwesomeIcons.compressAlt;
case "FontAwesomeIcons.compressArrowsAlt":
return FontAwesomeIcons.compressArrowsAlt;
case "FontAwesomeIcons.conciergeBell":
return FontAwesomeIcons.conciergeBell;
case "FontAwesomeIcons.confluence":
return FontAwesomeIcons.confluence;
case "FontAwesomeIcons.connectdevelop":
return FontAwesomeIcons.connectdevelop;
case "FontAwesomeIcons.contao":
return FontAwesomeIcons.contao;
case "FontAwesomeIcons.cookie":
return FontAwesomeIcons.cookie;
case "FontAwesomeIcons.cookieBite":
return FontAwesomeIcons.cookieBite;
case "FontAwesomeIcons.copy":
return FontAwesomeIcons.copy;
case "FontAwesomeIcons.copyright":
return FontAwesomeIcons.copyright;
case "FontAwesomeIcons.cottonBureau":
return FontAwesomeIcons.cottonBureau;
case "FontAwesomeIcons.couch":
return FontAwesomeIcons.couch;
case "FontAwesomeIcons.cpanel":
return FontAwesomeIcons.cpanel;
case "FontAwesomeIcons.creativeCommons":
return FontAwesomeIcons.creativeCommons;
case "FontAwesomeIcons.creativeCommonsBy":
return FontAwesomeIcons.creativeCommonsBy;
case "FontAwesomeIcons.creativeCommonsNc":
return FontAwesomeIcons.creativeCommonsNc;
case "FontAwesomeIcons.creativeCommonsNcEu":
return FontAwesomeIcons.creativeCommonsNcEu;
case "FontAwesomeIcons.creativeCommonsNcJp":
return FontAwesomeIcons.creativeCommonsNcJp;
case "FontAwesomeIcons.creativeCommonsNd":
return FontAwesomeIcons.creativeCommonsNd;
case "FontAwesomeIcons.creativeCommonsPd":
return FontAwesomeIcons.creativeCommonsPd;
case "":
return FontAwesomeIcons.creativeCommonsPdAlt;
default:
return FontAwesomeIcons.home;
}
}

View File

@ -0,0 +1,175 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
class CustomProfileTextField extends StatefulWidget {
CustomProfileTextField({
Key? key,
this.length = 999,
this.minLines = 1,
this.maxLines = 1,
this.height = 13,
this.noTitle = false,
this.prefix,
this.suffix,
this.color = secondaryColor,
this.borderColor = Colors.white,
this.keyboardType = TextInputType.text,
this.title = '',
this.obscuretext = false,
this.auto = false,
this.validate,
this.enable = true,
this.onChanged,
required this.pad,
required this.text,
required this.hinttext,
this.isErrorManual = false,
this.textErrorManual = '',
}) : super(key: key);
final int length;
final Color color;
final int minLines;
final int maxLines;
final bool noTitle;
final Color borderColor;
final TextInputType keyboardType;
final bool auto;
final String title;
final bool obscuretext;
final String text;
final String hinttext;
final double pad;
final double height;
// variabel untuk menangani error dari frontend
final FormFieldValidator<String>? validate;
final Widget? prefix;
final Widget? suffix;
final bool enable;
final Function(String)? onChanged;
// variabel untuk menangani error dari backend
final bool isErrorManual;
final String textErrorManual;
@override
State<CustomProfileTextField> createState() => _CustomProfileTextFieldState();
}
class _CustomProfileTextFieldState extends State<CustomProfileTextField> {
late final TextEditingController controller;
@override
void initState() {
super.initState();
controller = TextEditingController(text: widget.text);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final Brightness brightnessValue =
MediaQuery.of(context).platformBrightness;
bool isDarkMode = brightnessValue == Brightness.dark;
return Container(
margin: EdgeInsets.symmetric(horizontal: widget.pad),
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
widget.noTitle == false
? Text(
widget.title,
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(12),
),
)
: SizedBox(height: 0),
widget.noTitle == false
? SizedBox(
height: getProportionateScreenHeight(4),
)
: SizedBox(height: 0),
Theme(
data: ThemeData.dark().copyWith(errorColor: sevenColor),
child: TextFormField(
// initialValue: val,
enabled: widget.enable,
minLines: widget.minLines,
maxLines: widget.maxLines,
inputFormatters: [
LengthLimitingTextInputFormatter(widget.length),
],
keyboardType: widget.keyboardType,
autofocus: widget.auto,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: widget.validate,
obscureText: widget.obscuretext,
controller: controller,
onChanged: widget.onChanged,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
color: Theme.of(context).brightness == Brightness.dark
? secondaryColor
: baruTexthitam,
),
cursorColor: secondaryColor,
decoration: InputDecoration(
filled: true,
fillColor: Theme.of(context).brightness == Brightness.dark
? seventeenColor
: secondaryColor.withOpacity(0.3),
errorStyle: primaryTextStyle,
errorBorder: OutlineInputBorder(
borderSide: BorderSide(color: sevenColor),
borderRadius: BorderRadius.circular(10)),
suffixIcon: widget.suffix,
prefixIcon: widget.prefix,
contentPadding: EdgeInsets.only(
left: getProportionateScreenWidth(15),
top: getProportionateScreenHeight(widget.height),
bottom: getProportionateScreenHeight(widget.height)),
hintText: widget.hinttext,
hintStyle: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color: Theme.of(context).brightness == Brightness.dark
? widget.color
: baruTexthitam,
letterSpacing: 0.5),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(
10,
),
borderSide: BorderSide.none),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(
10,
),
// borderSide: BorderSide(
// color: widget.borderColor,
// ),
),
errorText: widget.isErrorManual ? widget.textErrorManual : null,
),
),
),
SizedBox(
height: getProportionateScreenHeight(16),
),
],
),
);
}
}

View File

@ -0,0 +1,149 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
class CustomTextField extends StatelessWidget {
CustomTextField({
Key? key,
this.length = 999,
this.minLines = 1,
this.maxLines = 1,
this.height = 13,
this.noTitle = false,
this.prefix,
this.suffix,
this.color = secondaryColor,
this.borderColor = Colors.white,
this.keyboardType = TextInputType.text,
this.title = '',
this.obscuretext = false,
this.auto = false,
this.validate,
this.enable = true,
required this.pad,
required this.controler,
required this.hinttext,
this.textInputAction,
this.digitOnly,
}) : super(key: key);
final int length;
final Color color;
final bool? digitOnly;
final int minLines;
final int maxLines;
final bool noTitle;
final Color borderColor;
final TextInputType keyboardType;
final bool auto;
final String title;
final bool obscuretext;
final TextEditingController controler;
final String hinttext;
final double pad;
final double height;
final FormFieldValidator<String>? validate;
final Widget? prefix;
final Widget? suffix;
final TextInputAction? textInputAction;
final bool enable;
// final String val;
@override
Widget build(BuildContext context) {
final Brightness brightnessValue =
MediaQuery.of(context).platformBrightness;
bool isDarkMode = brightnessValue == Brightness.dark;
return Container(
margin: EdgeInsets.symmetric(horizontal: pad),
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
noTitle == false
? Text(
title,
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(12),
// color: baruTexthitam,
letterSpacing: 0.5),
)
: SizedBox(height: 0),
noTitle == false
? SizedBox(
height: getProportionateScreenHeight(4),
)
: SizedBox(height: 0),
Theme(
data: ThemeData.dark(),
child: TextFormField(
// initialValue: val,
onChanged: (value) {},
enabled: enable,
minLines: minLines,
maxLines: maxLines,
inputFormatters: [
(digitOnly != null)
? (digitOnly!)
? FilteringTextInputFormatter.digitsOnly
: LengthLimitingTextInputFormatter(length)
: LengthLimitingTextInputFormatter(length)
],
keyboardType: keyboardType,
// autofocus: auto,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: validate,
obscureText: obscuretext,
controller: controler,
style: primaryTextStyle.copyWith(
color: Theme.of(context).brightness == Brightness.dark
? baruTextutih
: baruTexthitam,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
),
cursorColor: secondaryColor,
decoration: InputDecoration(
filled: true,
fillColor: Theme.of(context).brightness == Brightness.dark
? seventeenColor
: secondaryColor.withOpacity(0.3),
// errorStyle: primaryTextStyle,
// errorBorder: OutlineInputBorder(
// borderSide: BorderSide(color: sevenColor),
// borderRadius: BorderRadius.circular(10)),
errorStyle: thirdTextStyle.copyWith(color: Colors.red),
suffixIcon: suffix,
prefixIcon: prefix,
contentPadding: EdgeInsets.only(
left: getProportionateScreenWidth(15),
top: getProportionateScreenHeight(height),
bottom: getProportionateScreenHeight(height)),
hintText: hinttext,
hintStyle: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color: color,
letterSpacing: 0.5),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(
10,
),
borderSide: BorderSide.none),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(
10,
),
borderSide: BorderSide.none),
),
textInputAction: textInputAction,
),
),
SizedBox(
height: getProportionateScreenHeight(16),
),
],
),
);
}
}

View File

@ -0,0 +1,52 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:provider/provider.dart';
import '../../theme.dart';
import '../../size_config.dart';
class DefaultButton extends StatelessWidget {
const DefaultButton({
Key? key,
this.text = '',
this.weight = semiBold,
this.press,
this.isCart,
}) : super(key: key);
final String text;
final FontWeight weight;
final VoidCallback? press;
final bool? isCart;
@override
Widget build(BuildContext context) {
final themeProvider = Provider.of<ThemeProvider>(context);
return SizedBox(
width: isCart != null
? getProportionateScreenWidth(120)
: getProportionateScreenWidth(300),
height: isCart != null
? getProportionateScreenWidth(40)
: getProportionateScreenWidth(44),
child: TextButton(
style: TextButton.styleFrom(
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(getProportionateScreenWidth(10))),
backgroundColor: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode),
onPressed: press,
child: Text(
text,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: weight,
color: baruTextutih,
letterSpacing: 0.3),
),
),
);
}
}

View File

@ -0,0 +1,94 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:provider/provider.dart';
import '../../theme.dart';
import '../../size_config.dart';
class DefaultButtonPayment extends StatelessWidget {
const DefaultButtonPayment({
Key? key,
this.text = '',
this.weight = semiBold,
this.press,
this.isCart,
this.width,
this.height,
this.isInvoice,
}) : super(key: key);
final String text;
final FontWeight weight;
final VoidCallback? press;
final bool? isCart;
final bool? isInvoice;
final double? width;
final double? height;
@override
Widget build(BuildContext context) {
final themeProvider = Provider.of<ThemeProvider>(context);
return isInvoice == null
? SizedBox(
width: getProportionateScreenWidth(width ?? 0),
height: getProportionateScreenWidth(height ?? 0),
child: TextButton(
style: TextButton.styleFrom(
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
getProportionateScreenWidth(5),
),
),
backgroundColor: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
),
onPressed: press,
child: Text(
text,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: weight,
color: baruTextutih,
letterSpacing: 0.3),
),
),
)
: SizedBox(
width: getProportionateScreenWidth(width ?? 0),
height: getProportionateScreenWidth(height ?? 0),
child: TextButton(
style: TextButton.styleFrom(
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
getProportionateScreenWidth(5),
),
),
backgroundColor: primaryColor,
),
onPressed: press,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
Icons.file_download_outlined,
color: baruTextutih,
size: getProportionateScreenWidth(24),
),
SizedBox(width: getProportionateScreenWidth(3)),
Text(
text,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: weight,
color: baruTextutih,
letterSpacing: 0.3),
),
],
),
),
);
}
}

View File

@ -0,0 +1,64 @@
import 'package:flutter/material.dart';
import '../../theme.dart';
import '../../size_config.dart';
class DefaultIconButton extends StatelessWidget {
const DefaultIconButton(
{Key? key,
required this.icon,
required this.iconWidth,
required this.iconHeight,
this.text = '',
this.press,
this.color})
: super(key: key);
final String icon;
final String text;
final VoidCallback? press;
final double iconHeight;
final double iconWidth;
final Color? color;
@override
Widget build(BuildContext context) {
final Brightness brightnessValue =
MediaQuery.of(context).platformBrightness;
bool isDarkMode = brightnessValue == Brightness.dark;
return SizedBox(
width: double.infinity,
height: getProportionateScreenWidth(50),
child: TextButton.icon(
style: TextButton.styleFrom(
foregroundColor: Colors.white,
side: BorderSide(
width: getProportionateScreenWidth(0.15),
color: Theme.of(context).colorScheme.onBackground,
),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(getProportionateScreenWidth(10))),
// backgroundColor: tenthColor,
),
onPressed: press,
icon: Padding(
padding: EdgeInsets.only(right: getProportionateScreenWidth(1.0)),
child: Image.asset(
icon,
height: getProportionateScreenWidth(iconHeight),
width: getProportionateScreenWidth(iconWidth),
color: color,
),
),
label: Text(
text,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(14),
fontWeight: reguler,
color: Theme.of(context).colorScheme.onBackground,
),
),
),
);
}
}

View File

@ -0,0 +1,32 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/size_config.dart';
class FailedLogin extends StatelessWidget {
const FailedLogin(
{Key? key, this.text = '', required this.style, this.jarak = 8})
: super(key: key);
final String text;
final TextStyle style;
final double jarak;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Image.asset(
// 'assets/images/VOCASIA logo.png',
// width: getProportionateScreenWidth(150),
// height: getProportionateScreenHeight(50),
// ),
// SizedBox(height: getProportionateScreenHeight(jarak)),
Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Text(text,
maxLines: 2, textAlign: TextAlign.center, style: style),
),
],
);
}
}

View File

@ -0,0 +1,64 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/terms_and_privacy.dart';
import 'package:provider/provider.dart';
class Footer extends StatelessWidget {
const Footer(
{Key? key,
required this.textOne,
required this.textTwo,
required this.route,
this.height = 48.0})
: super(key: key);
final String textOne;
final String textTwo;
final String route;
final double height;
@override
Widget build(BuildContext context) {
final themeProvider = Provider.of<ThemeProvider>(context);
return Column(
children: [
Container(
// padding: EdgeInsets.only(
// left: getProportionateScreenWidth(5),
// top: getProportionateScreenWidth(5)),
alignment: Alignment.center,
child: RichText(
text: TextSpan(
children: <TextSpan>[
TextSpan(
text: textOne,
style: thirdTextStyle.copyWith(
color: fifteenColor,
),
),
TextSpan(
text: textTwo,
style: primaryTextStyle.copyWith(
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode, fontWeight: bold),
recognizer: TapGestureRecognizer()
..onTap = () {
Navigator.of(context).pushNamedAndRemoveUntil(
route, (Route<dynamic> route) => false);
//Navigator.pushNamed(context, route);
}),
],
style: primaryTextStyle.copyWith(
color: tenthColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
),
),
),
),
SizedBox(height: getProportionateScreenHeight(35)),
],
);
}
}

View File

@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
class Header extends StatelessWidget {
const Header(
{Key? key,
this.text = '',
this.text2 = '',
required this.style,
this.jarak = 20,
this.title = true})
: super(key: key);
final String text;
final String text2;
final TextStyle style;
final double jarak;
final bool title;
@override
Widget build(BuildContext context) {
final Brightness brightnessValue =
MediaQuery.of(context).platformBrightness;
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
title == true
? Image.asset(
isDarkMode
? 'assets/images/VOCASIA logo.png'
: 'assets/images/VOCASIA logo dark.png',
width: getProportionateScreenWidth(150),
height: getProportionateScreenHeight(50),
)
: Text(text2,
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
color: isDarkMode ? baruTextutih : baruTexthitam,
fontWeight: bold,
fontSize: getProportionateScreenWidth(20),
letterSpacing: 0.23)),
SizedBox(height: getProportionateScreenHeight(jarak)),
// Padding(
// padding:
// EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
// child: Text(text,
// maxLines: 2,
// textAlign: TextAlign.justify,
// style: thirdTextStyle.copyWith(
// color: isDarkMode ? baruTexthitam : baruTextutih,
// )),
// ),
],
);
}
}

View File

@ -0,0 +1,62 @@
import 'package:flutter/material.dart';
import '../../theme.dart';
import '../../size_config.dart';
class LoadingButton extends StatelessWidget {
const LoadingButton(
{Key? key,
required this.backgroundButtonColor,
required this.textButtonColor})
: super(key: key);
final Color backgroundButtonColor;
final Color textButtonColor;
@override
Widget build(BuildContext context) {
final Brightness brightnessValue =
MediaQuery.of(context).platformBrightness;
bool isDarkMode = brightnessValue == Brightness.dark;
return SizedBox(
width: double.infinity,
height: getProportionateScreenWidth(44),
child: TextButton(
style: TextButton.styleFrom(
foregroundColor: Colors.black,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(getProportionateScreenWidth(10))),
backgroundColor: backgroundButtonColor,
),
onPressed: () {},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 17,
height: 17,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation(
Color(0xffFFFFFF),
),
),
),
SizedBox(
width: getProportionateScreenWidth(6),
),
Text(
'Loading',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(14),
fontWeight: semiBold,
color: baruTextutih,
letterSpacing: 0.3),
),
],
),
),
);
}
}

View File

@ -0,0 +1,686 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/models/my_course_model.dart';
import 'package:initial_folder/providers/current_lesson_provider.dart';
import 'package:initial_folder/providers/detail_course_provider.dart';
import 'package:initial_folder/providers/instructor_provider.dart';
import 'package:initial_folder/providers/lesson_course_provider.dart';
import 'package:initial_folder/providers/my_course_provider.dart';
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:initial_folder/screens/course/play_course_page.dart';
import 'package:initial_folder/services/course_service.dart';
import 'package:initial_folder/services/instructor_service.dart';
import 'package:initial_folder/services/lesson_course_service.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:provider/provider.dart';
import 'package:shimmer/shimmer.dart';
import 'package:initial_folder/screens/detail_course/detail_course_screen.dart';
import 'package:initial_folder/providers/posting_review_provider.dart'
as postReviewProvider;
class MyCourseList extends StatefulWidget {
const MyCourseList({
Key? key,
required this.dataMyCourseModel,
this.onDialogClose,
}) : super(key: key);
final DataMyCourseModel dataMyCourseModel;
final VoidCallback? onDialogClose;
@override
State<MyCourseList> createState() => _MyCourseListState();
}
class _MyCourseListState extends State<MyCourseList> {
@override
void initState() {
super.initState();
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
}
@override
Widget build(BuildContext context) {
final themeProvider = Provider.of<ThemeProvider>(context);
final Brightness brightnessValue =
MediaQuery.of(context).platformBrightness;
bool isDarkMode = brightnessValue == Brightness.dark;
double value = 0.0;
if (widget.dataMyCourseModel.rating.length != 0) {
value = double.parse(widget.dataMyCourseModel.rating[0].rating!);
}
TextEditingController _controller = TextEditingController(
text: (widget.dataMyCourseModel.rating.length == 0)
? ""
: widget.dataMyCourseModel.rating[0].review);
final _formKey = GlobalKey<FormState>();
return Column(
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Theme.of(context).colorScheme.primaryContainer,
boxShadow: [
BoxShadow(
color: isDarkMode ? Colors.black : Colors.grey,
spreadRadius: 0.01,
blurRadius: 2,
offset: Offset(0, 1),
),
],
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(20),
right: getProportionateScreenWidth(20),
top: getProportionateScreenWidth(10),
bottom: 5),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailCourseScreen(
resoaktifitas: 'gada',
idcourse: widget.dataMyCourseModel.courseId ?? '1',
),
),
);
},
child: Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(10),
left: getProportionateScreenWidth(10),
top: getProportionateScreenHeight(10),
),
child: Column(
children: [
Padding(
padding: EdgeInsets.all(3),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
flex: 10,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
widget.dataMyCourseModel.title ?? ' ',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: SizeConfig.blockHorizontal! * 3.5,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
SizedBox(height: getProportionateScreenWidth(2)),
Text(
'${widget.dataMyCourseModel.instructor}',
style: thirdTextStyle.copyWith(
fontWeight: light,
color: Colors.grey.shade600,
fontSize: SizeConfig.blockHorizontal! * 3,
),
),
SizedBox(height: getProportionateScreenWidth(6)),
],
),
),
SizedBox(width: getProportionateScreenWidth(9)),
Flexible(
flex: 11,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CachedNetworkImage(
placeholder: (context, url) => Shimmer(
child: Container(
color: Colors.black,
),
gradient: LinearGradient(stops: [
0.2,
0.5,
0.6
], colors: [
ninthColor,
fourthColor,
ninthColor
])),
errorWidget: (context, url, error) =>
Icon(Icons.error),
imageBuilder: (context, imageUrl) => Container(
width: getProportionateScreenWidth(156),
height: getProportionateScreenWidth(88),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
image: DecorationImage(
fit: BoxFit.fill,
image: imageUrl,
),
),
),
imageUrl: widget.dataMyCourseModel.thumbnail ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg',
),
SizedBox(
height: getProportionateScreenHeight(8),
),
],
),
),
],
),
),
Align(
alignment: Alignment.topRight,
child: Text(
'Progres ${widget.dataMyCourseModel.totalProgress}%',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockHorizontal! * 3.5,
color: Colors.grey.shade600,
letterSpacing: 0.2,
),
),
),
Stack(
children: [
Container(
width: double.infinity,
height: getProportionateScreenHeight(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.grey.shade300),
),
Container(
width: (SizeConfig.screenWidth -
getProportionateScreenWidth(32)) *
int.parse(widget.dataMyCourseModel.totalProgress
.toString()) /
100,
height: getProportionateScreenHeight(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: primaryColor,
),
),
],
),
SizedBox(height: getProportionateScreenWidth(10)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
RatingBarIndicator(
itemSize: SizeConfig.blockHorizontal! * 3.5,
rating: double.parse(widget
.dataMyCourseModel.rating.isEmpty
? '0'
: widget.dataMyCourseModel.rating[0].rating ??
'5'),
direction: Axis.horizontal,
itemCount: 5,
itemBuilder: (context, index) {
if (index <
double.parse(
widget.dataMyCourseModel.rating.isEmpty
? '0'
: widget.dataMyCourseModel.rating[0]
.rating ??
'5')) {
return FaIcon(
FontAwesomeIcons.solidStar,
color: primaryColor,
);
} else {
return FaIcon(
FontAwesomeIcons.star,
color: primaryColor,
);
}
},
),
SizedBox(width: getProportionateScreenWidth(5)),
InkWell(
onTap: () => showDialog(
context: context,
builder: (context) => MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => postReviewProvider
.PostingReviewProvider(
courseService: CourseService(),
),
)
],
child: Consumer<
postReviewProvider.PostingReviewProvider>(
builder: (context, state, _) {
if (state.state ==
postReviewProvider
.ResultState.uninitilized) {
return AlertDialog(
surfaceTintColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(5)),
contentPadding: EdgeInsets.symmetric(
vertical: 10, horizontal: 10),
insetPadding: EdgeInsets.all(1),
backgroundColor: Theme.of(context)
.colorScheme
.background,
title: Center(
child: Text(
'Berikan Penilaian',
style: thirdTextStyle.copyWith(
fontSize: 15,
fontWeight: reguler,
letterSpacing: 0.2,
color: Theme.of(context)
.colorScheme
.background,
),
),
),
content: Container(
width:
getProportionateScreenWidth(300),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Form(
key: _formKey,
child: Column(
children: [
Container(
width:
getProportionateScreenWidth(
170),
height:
getProportionateScreenWidth(
100),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(
8),
image: DecorationImage(
fit: BoxFit.fill,
image: NetworkImage(widget
.dataMyCourseModel
.thumbnail ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg'),
),
),
),
SizedBox(
height:
getProportionateScreenWidth(
16)),
Text(
widget.dataMyCourseModel
.title ??
'',
style: thirdTextStyle
.copyWith(
letterSpacing: 1,
fontWeight:
reguler),
textAlign:
TextAlign.center),
SizedBox(
height:
getProportionateScreenWidth(
23),
),
RatingBar.builder(
minRating: 1,
itemPadding:
EdgeInsets.only(
left: 9),
initialRating: (widget
.dataMyCourseModel
.rating
.length ==
0)
? double.parse("0")
: double.parse(widget
.dataMyCourseModel
.rating[0]
.rating!),
itemSize: 25,
maxRating: 5,
itemBuilder:
(context, _) {
return FaIcon(
FontAwesomeIcons
.solidStar,
color: Colors
.orange[300]);
},
onRatingUpdate: (val) {
value = val;
}),
SizedBox(
height:
getProportionateScreenWidth(
16)),
SizedBox(
width:
getProportionateScreenWidth(
250),
child: TextFormField(
validator: (val) {
print(value);
if ((val == null ||
val.isEmpty) ||
value == 0.0) {
return 'Ulasan dan Rating tidak boleh kosong';
}
return null;
},
controller: _controller,
textInputAction:
TextInputAction.done,
cursorColor:
secondaryColor,
scrollPadding:
EdgeInsets.zero,
minLines: 2,
maxLines: null,
decoration:
InputDecoration(
filled: true,
fillColor: Theme.of(
context)
.brightness ==
Brightness.dark
? seventeenColor
: Colors.grey[200],
border:
OutlineInputBorder(
borderRadius:
BorderRadius
.circular(
10,
),
borderSide:
BorderSide
.none),
hintStyle:
secondaryTextStyle
.copyWith(
color: secondaryColor,
letterSpacing: 0.5,
fontSize:
getProportionateScreenWidth(
12),
),
hintText:
"Tulis Ulasan",
),
),
),
SizedBox(
height:
getProportionateScreenWidth(
10)),
ElevatedButton(
onPressed: () async {
if (_formKey.currentState!
.validate()) {
await state.postingReview(
_controller.text,
int.parse(widget
.dataMyCourseModel
.courseId
.toString()),
value.toInt());
await Provider.of<
MyCourseProvider>(
context,
listen: false)
.getMyCourse();
}
},
child: Text(
'Kirim Penilaian',
style: thirdTextStyle
.copyWith(
color:
Colors.white),
),
style: ElevatedButton
.styleFrom(
minimumSize: Size(
getProportionateScreenWidth(
150),
getProportionateScreenHeight(
33)),
backgroundColor:
primaryColor,
),
)
],
),
),
),
),
);
} else if (state.state ==
postReviewProvider
.ResultState.loading) {
return AlertDialog(
content: Container(
height:
getProportionateScreenHeight(40),
child: Center(
child: CircularProgressIndicator(
strokeWidth: 2,
color: primaryColor,
),
),
),
);
} else if (state.state ==
postReviewProvider
.ResultState.successUpdate) {
_controller.clear();
// widget.onDialogClose!();
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(10),
),
backgroundColor: Theme.of(context)
.colorScheme
.background,
surfaceTintColor: Colors.transparent,
contentPadding:
EdgeInsets.fromLTRB(12, 26, 22, 15),
content: Padding(
padding: EdgeInsets.only(
bottom:
getProportionateScreenHeight(
14)),
child: Container(
height:
getProportionateScreenHeight(
30),
child: Center(
child: Text(
'Berhasil mengedit ulasan',
style: primaryTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(
12),
letterSpacing: 0.5),
),
),
),
),
);
} else if (state.state ==
postReviewProvider
.ResultState.successAdd) {
_controller.clear();
// widget.onDialogClose!();
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(10),
),
backgroundColor: Theme.of(context)
.colorScheme
.background,
surfaceTintColor: Colors.transparent,
contentPadding: EdgeInsets.fromLTRB(
12, 26, 22, 15),
content: Padding(
padding: EdgeInsets.only(
bottom:
getProportionateScreenHeight(
14)),
child: Container(
height:
getProportionateScreenHeight(
30),
child: Center(
child: Text(
'Berhasil memberikan ulasan',
style: primaryTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(
12),
letterSpacing: 0.5),
),
),
),
));
} else if (state.state ==
postReviewProvider.ResultState.failed) {
return AlertDialog(
title: Text(
'Terjadi Kesalahan',
style: primaryTextStyle,
),
);
}
return AlertDialog(
title: Text(
'Terjadi Kesalahan',
style: primaryTextStyle,
),
);
},
),
),
),
child: widget.dataMyCourseModel.rating.isEmpty
? Text(
'Beri Penilaian',
style: thirdTextStyle.copyWith(
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
fontSize:
getProportionateScreenHeight(10),
),
)
: Text(
'Edit Penilaian',
style: thirdTextStyle.copyWith(
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
fontSize:
getProportionateScreenHeight(10),
),
),
)
],
),
SizedBox(),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) =>
CurrentLessonProvider(),
),
ChangeNotifierProvider(
create: (context) => LessonCourseProvider(
lessonCourseService:
LessonCourseService(),
id: int.parse(
widget.dataMyCourseModel.courseId ??
'0'),
),
),
ChangeNotifierProvider(
create: (context) => DetailCourseProvider(
courseService: CourseService(),
id: widget.dataMyCourseModel.courseId ??
'1'),
),
ChangeNotifierProvider(
create: (context) => InstructorProvider(
instructorService: InstructorService(),
id: int.parse(widget
.dataMyCourseModel.instructorId!),
),
),
],
child: PlayCourse(
judul: widget.dataMyCourseModel.title ?? '',
instruktur:
widget.dataMyCourseModel.instructor ?? '',
thumbnail: widget
.dataMyCourseModel.thumbnail ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg',
courseeid:
widget.dataMyCourseModel.courseId ?? '',
),
),
),
);
},
child: Text(
'Mulai',
style: thirdTextStyle.copyWith(
color: baruTextutih,
),
),
style: ElevatedButton.styleFrom(
minimumSize: Size(getProportionateScreenWidth(100),
getProportionateScreenHeight(33)),
backgroundColor: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10))),
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
),
),
),
],
);
}
}

View File

@ -0,0 +1,162 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/models/history_transaction_model.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
class NotifikasiList extends StatelessWidget {
const NotifikasiList(
{Key? key, this.berhasil = true, this.baru = false, required this.data})
: super(key: key);
final bool berhasil;
final bool baru;
final HistoryTransactionModel data;
@override
Widget build(BuildContext context) {
return Container(
color: (baru == false) ? Color(0xFF181818) : Color(0xFF212121),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(16),
right: getProportionateScreenWidth(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 12),
(data.statusPayment == 'Success')
? Row(
children: [
Container(
alignment: Alignment.center,
width: getProportionateScreenWidth(120),
height: getProportionateScreenWidth(24),
child: Text(
'Berhasil Dibayar',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: Colors.green[900],
fontSize: SizeConfig.blockHorizontal! * 2.6,
fontWeight: semiBold),
),
decoration: BoxDecoration(
color: Colors.green[300],
borderRadius: BorderRadius.circular(5),
//border: Border.all(color: kPrimaryColor),
),
),
SizedBox(width: getProportionateScreenWidth(8)),
Icon(Icons.lens_rounded,
color: Color(0xffc4c4c4),
size: getProportionateScreenWidth(7)),
SizedBox(width: getProportionateScreenWidth(8)),
Text(
DateFormat('Hm').format(data.date!),
style: primaryTextStyle.copyWith(
color: secondaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
letterSpacing: 0.5,
),
),
SizedBox(width: getProportionateScreenWidth(8)),
(baru == true)
? Icon(Icons.lens_rounded,
color: Color(0xffCD2228),
size: getProportionateScreenWidth(12))
: SizedBox(height: 0),
],
)
: Row(
children: [
Container(
alignment: Alignment.center,
width: getProportionateScreenWidth(165),
height: getProportionateScreenWidth(24),
child: Text(
'Menunggu Pembayaran',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: Colors.amber[900],
fontSize: SizeConfig.blockHorizontal! * 2.6,
fontWeight: semiBold),
),
decoration: BoxDecoration(
color: Colors.amber[200],
borderRadius: BorderRadius.circular(5),
//border: Border.all(color: kPrimaryColor),
),
),
SizedBox(width: getProportionateScreenWidth(8)),
Icon(Icons.lens_rounded,
color: Color(0xffc4c4c4),
size: getProportionateScreenWidth(7)),
SizedBox(width: getProportionateScreenWidth(8)),
Text(
DateFormat('Hm').format(data.date!),
style: primaryTextStyle.copyWith(
color: secondaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
letterSpacing: 0.5,
),
),
SizedBox(width: getProportionateScreenWidth(8)),
(baru == true)
? Icon(Icons.lens_rounded,
color: Color(0xffCD2228),
size: getProportionateScreenWidth(12))
: SizedBox(height: 0),
],
),
SizedBox(height: 9),
Text(
data.courses![0].title!,
style: primaryTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(13),
letterSpacing: 0.5,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
SizedBox(height: 9),
(data.statusPayment == 'Success')
? Text(
"Pembayaran berhasil dilakukan, kamu dapat mengikuti kursus sekarang!",
style: primaryTextStyle.copyWith(
color: secondaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
letterSpacing: 0.5,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
)
: Text(
"Selesaikan pembayaran sebelum ${DateFormat('E, d MMMM y').format(data.date!)} untuk mulai kursus",
style: primaryTextStyle.copyWith(
color: secondaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
letterSpacing: 0.5,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
SizedBox(height: 13),
],
),
),
Divider(
height: 1,
color: fourthColor,
),
],
),
);
}
}

View File

@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import '../size_config.dart';
import '../theme.dart';
class PointInstruktur extends StatelessWidget {
const PointInstruktur({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
children: [
SizedBox(
width: getProportionateScreenWidth(11),
),
CircleAvatar(
backgroundColor: primaryColor,
maxRadius: 2,
),
SizedBox(
width: getProportionateScreenWidth(10),
),
Text(
'Instruktur',
style: primaryTextStyle.copyWith(fontSize: 10, color: primaryColor),
)
],
);
}
}

123
lib/widgets/q_and_a.dart Normal file
View File

@ -0,0 +1,123 @@
// import 'package:flutter/material.dart';
// import 'package:initial_folder/models/announcement_model.dart';
// import 'package:initial_folder/screens/course/component/detail_quest_and_answer.dart';
// import 'package:initial_folder/theme.dart';
// import '../size_config.dart';
// class QandA extends StatelessWidget {
// const QandA(
// {Key? key,
// this.divider,
// this.pointInstruktur = const SizedBox(),
// required this.announcementDataModel})
// : super(key: key);
// final Widget? divider;
// final Widget pointInstruktur;
// final AnnouncementDataModel announcementDataModel;
// @override
// Widget build(BuildContext context) {
// return Container(
// margin: EdgeInsets.symmetric(
// horizontal: getProportionateScreenWidth(16),
// ),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// InkWell(
// onTap: () {
// print(announcementDataModel.idAnnouncement);
// },
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Row(
// children: [
// CircleAvatar(
// backgroundColor: primaryColor,
// ),
// SizedBox(
// width: getProportionateScreenWidth(8),
// ),
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Row(
// children: [
// Text(
// announcementDataModel.instructorName ?? ' ',
// style: primaryTextStyle.copyWith(
// fontSize: getProportionateScreenWidth(12),
// color: tenthColor),
// ),
// pointInstruktur,
// ],
// ),
// Text(
// announcementDataModel.date ?? '',
// style: primaryTextStyle.copyWith(
// fontSize: getProportionateScreenWidth(12),
// color: secondaryColor),
// ),
// ],
// ),
// ],
// ),
// SizedBox(height: getProportionateScreenHeight(3)),
// Text(
// announcementDataModel.bodyContent ?? '',
// style: secondaryTextStyle.copyWith(
// color: Color(0xffFFFFFF),
// letterSpacing: 1,
// fontSize: SizeConfig.blockHorizontal! * 3.4),
// ),
// SizedBox(height: getProportionateScreenHeight(16)),
// ],
// ),
// ),
// Row(
// children: [
// Icon(
// Icons.favorite_border,
// color: secondaryColor,
// size: 12,
// ),
// SizedBox(
// width: getProportionateScreenWidth(3),
// ),
// Text(
// announcementDataModel.likes ?? '',
// style: secondaryTextStyle.copyWith(
// fontSize: getProportionateScreenWidth(10),
// letterSpacing: 0.3),
// ),
// SizedBox(
// width: getProportionateScreenWidth(13),
// ),
// Icon(
// Icons.question_answer_rounded,
// color: secondaryColor,
// size: 12,
// ),
// SizedBox(
// width: getProportionateScreenWidth(3),
// ),
// Text(
// '50',
// style: secondaryTextStyle.copyWith(
// fontSize: getProportionateScreenWidth(10),
// letterSpacing: 0.3),
// )
// ],
// ),
// SizedBox(
// height: getProportionateScreenWidth(13),
// ),
// SizedBox(
// child: divider,
// )
// ],
// ),
// );
// }
// }

331
lib/widgets/qna_user.dart Normal file
View File

@ -0,0 +1,331 @@
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:initial_folder/main.dart';
import 'package:initial_folder/models/comment_qna_model.dart';
import 'package:initial_folder/models/qna_model.dart';
import 'package:initial_folder/providers/like_or_unlike_provider.dart';
import 'package:initial_folder/providers/posting_qna_provider.dart';
import 'package:initial_folder/providers/qna_provider.dart';
import 'package:initial_folder/screens/course/component/detail_quest_and_answer.dart';
import 'package:initial_folder/widgets/counter_qna_comment_page.dart';
import 'package:initial_folder/widgets/counter_qna_like_page.dart';
import 'package:initial_folder/widgets/edit_qna_user.dart';
import 'package:initial_folder/widgets/qna_user_page.dart';
import 'package:provider/provider.dart';
import '../get_it.dart';
import '../size_config.dart';
import '../theme.dart';
class QnaUser extends StatefulWidget {
const QnaUser({
Key? key,
required this.id,
this.divider,
required this.qnaDataModel,
required this.index,
required this.userId,
}) : super(key: key);
final Widget? divider;
final id;
final QnaDataModel qnaDataModel;
final int index;
final int userId;
@override
State<QnaUser> createState() => _QnaUserState();
}
class _QnaUserState extends State<QnaUser> {
double value = 0;
final provider = qnaGetIt<QnaProvider>();
// bool selfLike = false;
@override
Widget build(BuildContext context) {
PostingQnaProvider deleteQnaProvider =
Provider.of<PostingQnaProvider>(context);
deleteQna() async {
if (await deleteQnaProvider
.deleteQna(int.parse(widget.qnaDataModel.idQna.toString()))) {
ScaffoldMessenger.of(globalScaffoldKey.currentContext!).showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: primaryColor,
content: Text(
'Pertanyaan berhasil dihapus',
style: primaryTextStyle.copyWith(
color: backgroundColor,
),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
action: SnackBarAction(
label: 'Lihat',
onPressed: () {
ScaffoldMessenger.of(globalScaffoldKey.currentContext!)
.hideCurrentSnackBar();
},
),
),
);
} else {
ScaffoldMessenger.of(globalScaffoldKey.currentContext!).showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: primaryColor,
content: Text(
'Terjadi kesalahan',
style: primaryTextStyle.copyWith(
color: backgroundColor,
),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
);
}
}
LikeOrUnlikeProvider _likeOrUnlikeProvider =
Provider.of<LikeOrUnlikeProvider>(context);
likeOrUnlikes(int idQna) async {
final provider = qnaGetIt<QnaProvider>();
if (await _likeOrUnlikeProvider.likeOrUnlike(idQna)) {
provider.getQna(widget.id);
print("Respon Baik");
}
}
return Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailQuestAndAnswer(
qnaDataModel: widget.qnaDataModel,
id: widget.id,
index: widget.index,
userId: widget.userId,
),
),
).then((value) => provider.getQna(widget.id));
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
CircleAvatar(
backgroundColor: primaryColor,
backgroundImage: widget.qnaDataModel.fotoProfile == null
? AssetImage("assets/images/Profile Image.png")
: NetworkImage(widget.qnaDataModel.fotoProfile ?? '')
as ImageProvider,
),
SizedBox(
width: getProportionateScreenWidth(8),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
widget.qnaDataModel.username ?? '',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
color: Theme.of(context)
.colorScheme
.onBackground),
),
],
),
Text(
widget.qnaDataModel.date ?? '',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color:
Theme.of(context).colorScheme.onBackground),
),
],
),
int.parse(widget.qnaDataModel.sender.toString()) ==
widget.userId
? Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
PopupMenuButton(
child: Padding(
padding: EdgeInsets.only(right: 10),
child: Icon(
Icons.more_vert,
color: Theme.of(context)
.colorScheme
.onBackground,
),
),
itemBuilder: (context) => [
PopupMenuItem(
child: Container(
child: Text('Edit'),
),
value: 'edit',
),
PopupMenuItem(
child: Text('Hapus'),
value: 'hapus',
),
],
onSelected: (value) {
switch (value) {
case 'edit':
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => EditQna(
quest: widget.qnaDataModel.quest,
title: widget.qnaDataModel.title,
id_qna: widget.qnaDataModel.idQna,
id_course: widget.id,
id_lesson:widget.qnaDataModel.idLesson,
),
),
);
break;
case 'hapus':
deleteQna();
break;
}
},
),
],
),
)
: SizedBox(
height: 12,
),
],
),
SizedBox(height: getProportionateScreenHeight(6)),
widget.qnaDataModel.title != ''
? Text(
widget.qnaDataModel.title!,
style: secondaryTextStyle.copyWith(
color: Theme.of(context).colorScheme.onBackground,
fontSize: SizeConfig.blockHorizontal! * 4.2,
fontWeight: FontWeight.bold,
),
)
: const SizedBox(),
Html(
data: widget.qnaDataModel.quest ?? '',
style: {
"*": Style(margin: Margins.zero),
},
),
// Text(
// widget.qnaDataModel.quest ?? '',
// style: secondaryTextStyle.copyWith(
// color: Theme.of(context).colorScheme.onBackground,
// letterSpacing: 1,
// fontSize: SizeConfig.blockHorizontal! * 3.4),
// ),
SizedBox(height: getProportionateScreenHeight(16)),
],
),
),
Row(
children: [
kLike(
widget.qnaDataModel.selfLiked == true
? Icons.favorite
: Icons.favorite_border_rounded,
widget.qnaDataModel.selfLiked == true
? Colors.red
: secondaryColor, () {
likeOrUnlikes(int.parse(widget.qnaDataModel.idQna.toString()));
}),
SizedBox(
width: getProportionateScreenWidth(3),
),
Text(
"${widget.qnaDataModel.countLike ?? 0}",
style: secondaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
letterSpacing: 0.3),
),
SizedBox(
width: getProportionateScreenWidth(13),
),
kComment(
widget.qnaDataModel.comment.length,
),
],
),
SizedBox(
height: getProportionateScreenWidth(5),
),
Divider(
thickness: 0.3,
)
// SizedBox(
// child: widget.divider,
// )
],
),
);
}
}
Widget kLike(IconData icon, Color color, Function onTap) {
return GestureDetector(
onTap: () => onTap(),
child: Row(
children: [
Icon(
icon,
color: color,
size: 12,
),
],
),
);
}
Widget kComment(int value) {
return Row(
children: [
Icon(
FontAwesomeIcons.comment,
color: secondaryColor,
size: 12,
),
SizedBox(
width: getProportionateScreenWidth(3),
),
Text(
"$value",
style: secondaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10), letterSpacing: 0.3),
)
],
);
}

View File

@ -0,0 +1,131 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/models/qna_model.dart';
import 'package:initial_folder/providers/qna_provider.dart';
import 'package:initial_folder/widgets/qna_user.dart';
import '../get_it.dart';
import '../theme.dart';
class QnaUserPage extends StatefulWidget {
const QnaUserPage({Key? key, required this.idCourse}) : super(key: key);
final idCourse;
@override
State<QnaUserPage> createState() => _QnaUserPageState();
}
class _QnaUserPageState extends State<QnaUserPage> {
final provider = qnaGetIt<QnaProvider>();
int? userId = 0;
void getUserId() async {
userId = await UsersInfo().getIdUser();
}
@override
void initState() {
// TODO: implement initState
getUserId();
super.initState();
}
@override
Widget build(BuildContext context) {
provider.getQna(widget.idCourse);
late Widget build;
return StreamBuilder<QnaModel>(
stream: provider.qnaStream,
builder: (context, AsyncSnapshot<QnaModel> snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(
'Terjadi Kesalahan',
style: thirdTextStyle,
),
);
} else {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
build = Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
break;
case ConnectionState.none:
build = Center(
child: Text(
'Tidak ada koneksi',
style: thirdTextStyle,
),
);
break;
case ConnectionState.active:
if (snapshot.data!.data[0].isEmpty) {
build = Center(
child: Text(
'Tidak Ada Pertanyaan',
style: thirdTextStyle,
),
);
} else {
print('masuk siniiiiiiiiiii active');
// build = Text(snapshot.data!.status.toString());
build = ListView.builder(
itemCount: snapshot.data!.data[0].length,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return QnaUser(
divider: Divider(),
qnaDataModel: snapshot.data!.data[0][index],
id: widget.idCourse,
index: index,
userId: userId!,
);
},
);
}
break;
case ConnectionState.done:
if (snapshot.data!.data[0].isEmpty) {
build = Center(
child: Text(
'Belum ada pertanyaan',
style: thirdTextStyle,
),
);
} else {
print('masuk siniiiiiiiiiii done');
build = ListView.builder(
itemCount: snapshot.data!.data[0].length,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return QnaUser(
divider: Divider(
thickness: 3.0,
),
qnaDataModel: snapshot.data!.data[0][index],
id: widget.idCourse,
index: index,
userId: userId!,
);
},
);
}
break;
}
}
return build;
},
);
}
}

View File

@ -0,0 +1,100 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/models/announcement_model.dart';
import 'package:initial_folder/models/reply_announcement_model.dart';
import '../size_config.dart';
import '../theme.dart';
class ReplyAnnouncementUser extends StatefulWidget {
const ReplyAnnouncementUser(
{Key? key,
required this.announcementDataModel,
required this.divider,
required this.replyModel,
required this.userId})
: super(key: key);
final Widget? divider;
final ReplyModel replyModel;
final int userId;
final AnnouncementDataModel announcementDataModel;
@override
State<ReplyAnnouncementUser> createState() => _ReplyAnnouncementUserState();
}
class _ReplyAnnouncementUserState extends State<ReplyAnnouncementUser> {
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 6,
),
Row(
children: [
CircleAvatar(
backgroundColor: primaryColor,
backgroundImage: widget.replyModel.fotoProfile == null
? AssetImage("assets/images/Profile Image.png")
: NetworkImage(widget.replyModel.fotoProfile ?? '')
as ImageProvider,
),
SizedBox(width: getProportionateScreenWidth(8)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
InkWell(
onTap: () {
print(
'Print ${widget.announcementDataModel.tokenAnnouncement}');
},
child: Text(
widget.replyModel.name ?? '',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color: Theme.of(context)
.colorScheme
.onBackground),
),
),
],
),
Text(
widget.replyModel.createAt ?? '',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color: Theme.of(context).colorScheme.onBackground),
),
],
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Text(
widget.replyModel.body ?? '',
style: thirdTextStyle.copyWith(
color: Theme.of(context).colorScheme.onBackground,
letterSpacing: 1,
fontSize: SizeConfig.blockHorizontal! * 3.4),
),
],
),
SizedBox(height: getProportionateScreenHeight(6)),
// SizedBox(child: widget.divider)
Divider(
thickness: 0.3,
)
],
),
);
}
}

View File

@ -0,0 +1,119 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/models/announcement_model.dart';
import 'package:initial_folder/providers/reply_announcement_provider.dart';
import 'package:initial_folder/widgets/reply_announcement_user.dart';
import '../get_it.dart';
import '../theme.dart';
class ReplyAnnouncementUserPage extends StatefulWidget {
const ReplyAnnouncementUserPage({
Key? key,
required this.idCourse,
required this.index,
required this.userId,
}) : super(key: key);
final idCourse;
final int index;
final int userId;
@override
State<ReplyAnnouncementUserPage> createState() =>
_ReplyAnnouncementUserPageState();
}
class _ReplyAnnouncementUserPageState extends State<ReplyAnnouncementUserPage> {
final provider = replyAnnouncementGetIt<ReplyAnnouncementProvider>();
@override
Widget build(BuildContext context) {
provider.getReplyAnnouncement(widget.idCourse, widget.index);
late Widget build;
return StreamBuilder<AnnouncementModel>(
stream: provider.replyAnnouncementStream,
builder: (context, AsyncSnapshot<AnnouncementModel> snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(
'Terjadi Kesalahan',
style: thirdTextStyle,
),
);
} else {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
build = Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
break;
case ConnectionState.none:
build = Center(
child: Text(
'Tidak ada koneksi',
style: thirdTextStyle,
),
);
break;
case ConnectionState.active:
build = snapshot.data!.data[0][widget.index].replies.length > 0
? ListView.builder(
itemCount:
snapshot.data!.data[0][widget.index].replies.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
var replyModel =
snapshot.data!.data[0][widget.index].replies[index];
var announcementuser =
snapshot.data!.data[0][widget.index];
return ReplyAnnouncementUser(
divider: Divider(),
replyModel: replyModel,
announcementDataModel: announcementuser,
userId: widget.userId,
);
})
: Center(
child: Text(
'Belum ada pengumuman',
style: thirdTextStyle,
),
);
break;
case ConnectionState.done:
build = snapshot.data!.data[0][widget.index].replies.length > 0
? ListView.builder(
itemCount:
snapshot.data!.data[0][widget.index].replies.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
var replyModel =
snapshot.data!.data[0][widget.index].replies[index];
var announcementuser =
snapshot.data!.data[0][widget.index];
return ReplyAnnouncementUser(
divider: Divider(),
replyModel: replyModel,
announcementDataModel: announcementuser,
userId: widget.userId,
);
})
: Center(
child: Text(
'Belum ada pertanyaan',
style: thirdTextStyle,
),
);
break;
}
}
return build;
},
);
}
}

View File

@ -0,0 +1,215 @@
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:initial_folder/main.dart';
import 'package:initial_folder/models/comment_qna_model.dart';
import 'package:initial_folder/models/qna_model.dart';
import 'package:initial_folder/providers/posting_qna_reply_provider.dart';
import 'package:initial_folder/screens/course/component/detail_quest_and_answer.dart';
import 'package:initial_folder/widgets/edit_reply_qna_user.dart';
import 'package:provider/provider.dart';
import '../size_config.dart';
import '../theme.dart';
class ReplyQnaUser extends StatefulWidget {
const ReplyQnaUser(
{Key? key,
required this.qnaDataModel,
required this.divider,
required this.comment,
required this.userId,
required this.onDeleteReply,})
: super(key: key);
final Widget? divider;
final Comment comment;
final int userId;
final QnaDataModel qnaDataModel;
final Function(String idRep) onDeleteReply;
@override
State<ReplyQnaUser> createState() => _ReplyQnaUserState();
}
class _ReplyQnaUserState extends State<ReplyQnaUser> {
@override
Widget build(BuildContext context) {
PostingQnaReplyProvider deleteReplyQnaProvider =
Provider.of<PostingQnaReplyProvider>(context);
deleteReplyQna() async {
if (await deleteReplyQnaProvider.deleteReplyQna(int.parse(widget.comment.idRep!))) {
// Notify the parent widget about the deletion
widget.onDeleteReply(widget.comment.idRep!);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: primaryColor,
content: Text(
'Balasan berhasil dihapus',
style: primaryTextStyle.copyWith(
color: Colors.white,
),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
);
} else {
// Handle the error case
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: primaryColor,
content: Text(
'Terjadi kesalahan',
style: primaryTextStyle.copyWith(
color: backgroundColor,
),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
);
}
}
return Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 6,
),
Row(
children: [
CircleAvatar(
backgroundColor: primaryColor,
backgroundImage: widget.comment.fotoProfile == null
? AssetImage("assets/images/Profile Image.png")
: NetworkImage(widget.comment.fotoProfile ?? '')
as ImageProvider,
),
SizedBox(
width: getProportionateScreenWidth(8),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
InkWell(
onTap: () {
print('Print ${widget.qnaDataModel.idQna}');
},
child: Text(
widget.comment.username ?? '',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color: Theme.of(context)
.colorScheme
.onBackground),
),
),
],
),
Text(
widget.comment.createAt ?? '',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color: Theme.of(context).colorScheme.onBackground),
),
],
),
int.parse(widget.comment.sender.toString()) == widget.userId
? Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
PopupMenuButton(
child: Padding(
padding: EdgeInsets.only(right: 10),
child: Icon(
Icons.more_vert,
color: Theme.of(context)
.colorScheme
.onBackground,
),
),
itemBuilder: (context) => [
PopupMenuItem(
child: Container(
child: Text('Edit'),
),
value: 'edit',
),
PopupMenuItem(
child: Text('Hapus'),
value: 'hapus',
),
],
onSelected: (value) {
switch (value) {
case 'edit':
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => EditReplyQna(
id_qna: widget.qnaDataModel.idQna,
text_rep: widget.comment.textRep,
id_rep: widget.comment.idRep,
),
),
);
break;
case 'hapus':
print(widget.comment.idRep);
deleteReplyQna();
break;
}
},
),
],
),
)
: SizedBox(
height: 12,
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Html(
data: widget.comment.textRep ?? '',
style: {
"*": Style(margin: Margins.zero),
},
),
// Text(
// widget.comment.textRep ?? '',
// style: thirdTextStyle.copyWith(
// color: Theme.of(context).colorScheme.onBackground,
// letterSpacing: 1,
// fontSize: SizeConfig.blockHorizontal! * 3.4),
// ),
SizedBox(height: getProportionateScreenHeight(6)),
],
),
Divider(
thickness: 0.3,
)
],
),
);
}
}

View File

@ -0,0 +1,123 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/models/qna_model.dart';
import 'package:initial_folder/providers/reply_qna_provider.dart';
import 'package:initial_folder/widgets/reply_qna_user.dart';
import '../get_it.dart';
import '../theme.dart';
class ReplyQnaUserPage extends StatefulWidget {
const ReplyQnaUserPage({
Key? key,
required this.idCourse,
required this.idQna,
required this.userId, required this.onReplyDeleted,
}) : super(key: key);
final idCourse;
final String idQna;
final int userId;
final Function(String idRep) onReplyDeleted;
@override
State<ReplyQnaUserPage> createState() => _ReplyQnaUserPageState();
}
class _ReplyQnaUserPageState extends State<ReplyQnaUserPage> {
final provider = replyQnaGetIt<ReplyQnaProvider>();
@override
Widget build(BuildContext context) {
provider.getReplyQnaById(widget.idCourse, widget.idQna);
late Widget build;
return StreamBuilder<QnaModel>(
stream: provider.replyQnaStream,
builder: (context, AsyncSnapshot<QnaModel> snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(
'Terjadi Kesalahan',
style: thirdTextStyle,
),
);
} else {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
build = Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
break;
case ConnectionState.none:
build = Center(
child: Text(
'Tidak ada koneksi',
style: thirdTextStyle,
),
);
break;
case ConnectionState.active:
// build = snapshot.data!.data[0][widget.index].comment.length > 0
// ? ListView.builder(
// itemCount:
// snapshot.data!.data[0][widget.index].comment.length,
// shrinkWrap: true,
// physics: NeverScrollableScrollPhysics(),
// itemBuilder: (context, index) {
// var comment = snapshot
// .data!.data[0][widget.index].comment[index];
// var qnauser = snapshot.data!.data[0][widget.index];
// return ReplyQnaUser(
// divider: Divider(),
// comment: comment,
// qnaDataModel: qnauser,
// userId: widget.userId,
// );
// })
// : Center(
// child: Text(
// 'Belum ada pertanyaan',
// style: thirdTextStyle,
// ),
// );
// break;
case ConnectionState.done:
if (snapshot.hasData && snapshot.data!.data.isNotEmpty) {
final qnaData = snapshot.data!.data[0];
return ListView.builder(
itemCount: qnaData.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
var comment = qnaData[index].comment;
return Column(
children: comment.map((commentItem) {
return ReplyQnaUser(
divider: Divider(),
comment: commentItem,
qnaDataModel: qnaData[index],
userId: widget.userId,onDeleteReply: widget.onReplyDeleted,
);
}).toList(),
);
},
);
} else {
return Center(
child: Text(
'Belum ada balasan',
style: thirdTextStyle,
),
);
}
// break;
}
}
return build;
});
}
}

View File

@ -0,0 +1,425 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/models/history_transaction_model.dart';
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:initial_folder/screens/checkout/snap_payment_page.dart';
import 'package:initial_folder/services/history_transactions_service.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:shimmer/shimmer.dart';
class RiwayatList extends StatelessWidget {
RiwayatList({Key? key, required this.dataHistoryTransactionModel})
: super(key: key);
final HistoryTransactionModel dataHistoryTransactionModel;
final Map<String, String> status = {
'null': "Dibatalkan",
'1': 'Berhasil',
'0': 'Transaksi Kursus Gratis',
'2': 'Menunggu Pembayaran',
'-1': 'Pembayaran Ditolak',
'-2': 'Melebihi Batas Waktu',
'-3': 'Dibatalkan',
'-5': 'Belum Pilih Metode Pembayaran',
};
final Map<String, String> paymentType = {
'null': "Dibatalkan",
'bank transfer': 'Bank Transfer',
'echannel': 'Bank Transfer',
'credit card': 'Kartu Kredit',
'permata': 'Bank Transfer',
'gopay': 'GoPay',
'cstore': 'Gerai',
'free': 'Kursus Gratis',
'Coupon Free Course': 'Kursus Gratis',
'qris': 'QRIS'
};
Widget _statusLabel(String text, Color color) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(4),
horizontal: getProportionateScreenWidth(5)),
child: Text(
text,
style: thirdTextStyle.copyWith(
color: baruTextutih,
fontSize: getProportionateScreenWidth(9),
fontWeight: semiBold,
),
),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(5),
),
);
}
Widget _customButton({VoidCallback? onTap, String? text}) {
return InkWell(
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: Color.fromARGB(120, 18, 140, 126)),
borderRadius: BorderRadius.circular(5)),
padding: EdgeInsets.symmetric(vertical: 15),
child: Center(
child: Text(
text!,
style: thirdTextStyle.copyWith(
fontWeight: semiBold, fontSize: 12, letterSpacing: 0.32),
),
),
),
onTap: onTap,
);
}
Widget _listCourse(String? thumbnail, String? title) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Flexible(
flex: 34,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CachedNetworkImage(
imageUrl: thumbnail == null || thumbnail.isEmpty
? '$baseUrl/images/default-thumbnail.png'
: thumbnail.startsWith("http")
? thumbnail
: '$baseUrl/uploads/thumbnail/course_thumbnails/$thumbnail',
imageBuilder: (context, imageProvider) => Container(
width: getProportionateScreenWidth(100),
height: getProportionateScreenWidth(43),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
image: DecorationImage(
fit: BoxFit.cover,
image: imageProvider,
),
),
),
placeholder: (context, url) => Shimmer(
child: Container(
color: thirdColor,
),
gradient: LinearGradient(
stops: [0.4, 0.5, 0.6],
colors: [secondaryColor, thirdColor, secondaryColor],
),
),
errorWidget: (context, url, error) => Container(
width: getProportionateScreenWidth(108),
height: getProportionateScreenWidth(50),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(
'https://api.vokasia.id/images/default-thumbnail.png'),
),
),
),
),
],
),
),
SizedBox(width: getProportionateScreenWidth(10)),
Flexible(
flex: 96,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
title ?? ' ',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
),
),
],
),
);
}
@override
Widget build(BuildContext context) {
final themeProvider = Provider.of<ThemeProvider>(context);
return Container(
margin: EdgeInsets.only(
bottom: getProportionateScreenWidth(10),
left: getProportionateScreenWidth(16),
right: getProportionateScreenWidth(16)),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(4),
boxShadow: [
BoxShadow(
color: Theme.of(context).brightness == Brightness.dark
? Colors.transparent
: secondaryColor.withOpacity(0.5),
offset: Offset(0, 2),
blurRadius: 2,
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.only(
top: getProportionateScreenWidth(16),
left: getProportionateScreenWidth(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
// Order ID
dataHistoryTransactionModel.orderId ?? '',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
),
Row(
children: [
Text(
dataHistoryTransactionModel.date != null
? DateFormat.MMMMEEEEd()
.format(dataHistoryTransactionModel.date!)
: '',
style: thirdTextStyle.copyWith(
color: secondaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
),
SizedBox(width: getProportionateScreenWidth(12)),
if (dataHistoryTransactionModel.statusPayment != null &&
(dataHistoryTransactionModel.statusPayment == '1' ||
dataHistoryTransactionModel.statusPayment == '0'))
_statusLabel(
status[dataHistoryTransactionModel.statusPayment]! ??
'',
eightColor)
else if (dataHistoryTransactionModel.statusPayment == '2' ||
dataHistoryTransactionModel.statusPayment == '0')
_statusLabel(
status[dataHistoryTransactionModel.statusPayment]! ??
'',
fiveColor)
else if (dataHistoryTransactionModel.statusPayment !=
null &&
status.containsKey(
dataHistoryTransactionModel.statusPayment))
_statusLabel(
status[dataHistoryTransactionModel.statusPayment]!,
sevenColor)
else
_statusLabel("${status['null']}", sevenColor)
],
),
],
),
),
Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(8)),
),
Container(
margin: EdgeInsets.only(
top: getProportionateScreenWidth(12),
left: getProportionateScreenWidth(8),
right: getProportionateScreenWidth(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Kursus",
style: primaryTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
letterSpacing: 0.5,
),
),
SizedBox(height: 8),
Column(
children: dataHistoryTransactionModel.courses != null
? dataHistoryTransactionModel.courses!
.map((course) =>
_listCourse(course.thumbnail, course.title))
.toList()
: [],
),
],
),
),
Container(
margin: EdgeInsets.only(
top: getProportionateScreenHeight(7),
left: getProportionateScreenWidth(12),
right: getProportionateScreenWidth(20),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
"Jenis Pembayaran",
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
),
Spacer(),
Text(
dataHistoryTransactionModel.paymentDetail != null &&
dataHistoryTransactionModel
.paymentDetail!.paymentType !=
null &&
paymentType.containsKey(dataHistoryTransactionModel
.paymentDetail!.paymentType)
? paymentType[dataHistoryTransactionModel
.paymentDetail!.paymentType]!
.toUpperCase()
: 'Belum Memilih',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
Text(
"Total Pembelian",
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
),
Spacer(),
Text(
"Rp. ${dataHistoryTransactionModel.paymentDetail?.paymentType != "Coupon Free Course" ? dataHistoryTransactionModel.totalPrice?.toString() ?? '' : "0"}",
style: thirdTextStyle.copyWith(
fontWeight: bold,
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: 15),
dataHistoryTransactionModel.statusPayment == '1' &&
dataHistoryTransactionModel
.paymentDetail!.paymentType !=
'free'
? Column(
children: [
_customButton(text: 'Receipt'),
SizedBox(
height: getProportionateScreenHeight(10),
),
// _customButton(text: 'Invoice'),
// SizedBox(
// height: getProportionateScreenHeight(20),
// ),
],
)
: dataHistoryTransactionModel.statusPayment == '-5'
? Padding(
padding: const EdgeInsets.only(top: 10, bottom: 15),
child: Column(
children: [
InkWell(
onTap: () async {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => Center(
child: CircularProgressIndicator(),
),
);
try {
String orderId = dataHistoryTransactionModel.orderId ?? '';
await HistoryTransactionService().checkTransactionExpiration(orderId);
Navigator.of(context).pop();
} catch (e) {
Navigator.of(context).pop();
print('Error saat memeriksa status transaksi: $e');
}
var redirectUrl = dataHistoryTransactionModel.token;
if (redirectUrl != null && redirectUrl.isNotEmpty) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SnapPaymentPage(
transactionToken: redirectUrl,
orderId: dataHistoryTransactionModel.orderId ?? '',
grossAmount: dataHistoryTransactionModel.totalPrice ?? 0,
courseTitle: '',
courseThumbnail: '',
courseInstructor: '',
courseId: '',
),
),
);
} else {
print("Pembayaran belum dimulai atau URL pembayaran tidak ada.");
}
},
child: Container(
width: double.infinity,
padding: EdgeInsets.symmetric(vertical: 15),
child: Center(
child: Text(
'Lanjutkan Pembayaran',
style: thirdTextStyle.copyWith(
fontSize: 12,
fontWeight: semiBold,
color: Colors.white,
),
),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
),
),
),
],
),
)
: Container()
],
),
),
],
),
);
}
}

View File

@ -0,0 +1,688 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/models/history_transaction_model.dart';
import 'package:initial_folder/providers/detail_invoice_provider.dart';
import 'package:initial_folder/providers/order_provider.dart';
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/screens/checkout/batas_bayar.dart';
import 'package:initial_folder/screens/checkout/gopay/batas_bayar_gopay.dart';
import 'package:initial_folder/screens/profile/account_sign_in/detail_transaksi.dart';
import 'package:initial_folder/services/cancel_payment_service.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
import 'package:initial_folder/widgets/login_regist/default_button_payment.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:shimmer/shimmer.dart';
import '../screens/checkout/snap_payment_page.dart';
class RiwayatListDelete extends StatefulWidget {
RiwayatListDelete({
Key? key,
required this.dataHistoryTransactionModel,
required this.onPaymentCancelled,
}) : super(key: key);
final HistoryTransactionModel dataHistoryTransactionModel;
final Function(String) onPaymentCancelled;
@override
State<RiwayatListDelete> createState() => _RiwayatListDeleteState();
}
class _RiwayatListDeleteState extends State<RiwayatListDelete> {
bool isLoading = false;
final Map<String, String> status = {
'null': "Dibatalkan",
'1': 'Berhasil',
'0': 'Transaksi Kursus Gratis',
'2': 'Menunggu Pembayaran',
'-1': 'Pembayaran Ditolak',
'-2': 'Melebihi Batas Waktu',
};
final Map<String, String> paymentType = {
'null': "Kartu Kredit",
'credit card': 'Kartu Kredit',
'qris': 'QRIS',
'free': 'Kursus Gratis'
};
final Map<String, String> bank = {
'null': "Kartu Kredit",
'bni': 'BNI Virtual Account',
'bca': 'BCA Virtual Account',
'Mandiri': 'Mandiri Virtual Account',
'Permata': 'Permata Virtual Account',
'qris': 'QR Code',
'free': 'Kursus Gratis'
};
final Map<String, String> store = {
'null': "Kartu Kredit",
'indomaret': 'Indomaret',
'alfamart': 'Alfamart',
'free': 'Kursus Gratis'
};
Widget _statusLabel(String text, Color color) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(5),
horizontal: getProportionateScreenWidth(5)),
child: Text(
text,
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: backgroundColor,
fontSize: SizeConfig.blockHorizontal! * 2.5,
fontWeight: semiBold),
),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(5),
),
);
}
Widget _customButton({VoidCallback? onTap, String? text}) {
return InkWell(
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: Color.fromARGB(120, 18, 140, 126)),
borderRadius: BorderRadius.circular(5)),
padding: EdgeInsets.symmetric(vertical: 15),
child: Center(
child: Text(
text!,
style: thirdTextStyle.copyWith(
fontWeight: semiBold, fontSize: 12, letterSpacing: 0.32),
)),
),
onTap: onTap,
);
}
Widget _listCourse(String? thumbnail, String? title) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Flexible(
flex: 34,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CachedNetworkImage(
imageUrl: thumbnail != null && thumbnail.isNotEmpty
? '$baseUrl/uploads/thumbnail/course_thumbnails/$thumbnail'
: '$baseUrl/images/default-thumbnail.png',
imageBuilder: (context, imageProvider) => Container(
width: getProportionateScreenWidth(100),
height: getProportionateScreenWidth(43),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
image: DecorationImage(
fit: BoxFit.cover,
image: imageProvider,
),
),
),
placeholder: (context, url) => Shimmer(
child: Container(
color: thirdColor,
),
gradient: LinearGradient(stops: [
0.4,
0.5,
0.6
], colors: [
secondaryColor,
thirdColor,
secondaryColor
])),
errorWidget: (context, url, error) => Container(
width: getProportionateScreenWidth(108),
height: getProportionateScreenWidth(50),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(
thumbnail == null || thumbnail.isEmpty
? '$baseUrl/images/default-thumbnail.png'
: thumbnail.startsWith("http")
? thumbnail
: '$baseUrl/uploads/thumbnail/course_thumbnails/$thumbnail',
)),
),
),
),
],
)),
SizedBox(width: getProportionateScreenWidth(10)),
Flexible(
flex: 96,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
title ?? ' ',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
),
),
],
),
);
}
@override
Widget build(BuildContext context) {
var selected = Provider.of<TotalPriceProvider>(context);
var selectedInvoice = Provider.of<DetailInvoiceProvider>(context);
final themeProvider = Provider.of<ThemeProvider>(context);
return Container(
margin: EdgeInsets.only(
bottom: getProportionateScreenWidth(10),
left: getProportionateScreenWidth(16),
right: getProportionateScreenWidth(16)),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(4),
boxShadow: [
BoxShadow(
color: Theme.of(context).brightness == Brightness.dark
? Colors.transparent
: secondaryColor.withOpacity(0.5),
offset: Offset(0, 2),
blurRadius: 2,
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.only(
top: getProportionateScreenHeight(9),
left: getProportionateScreenWidth(9),
right: getProportionateScreenWidth(9),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${widget.dataHistoryTransactionModel.orderId!}",
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
),
Text(
"Bayar Sebelum",
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
color: secondaryColor,
),
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
DateFormat('dd MMMM yyyy')
.format(widget.dataHistoryTransactionModel.date!),
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
fontFamily: "Poppins",
),
),
SizedBox(width: getProportionateScreenWidth(8)),
Container(
decoration: BoxDecoration(
color: sevenColor,
borderRadius: BorderRadius.circular(4),
),
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(3),
vertical: getProportionateScreenHeight(1),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Icon(
Icons.access_time,
size: getProportionateScreenWidth(14),
color: baruTextutih,
),
SizedBox(width: getProportionateScreenWidth(2)),
Text(
DateFormat('dd MMMM HH:mm').format(widget
.dataHistoryTransactionModel.date!
.add(Duration(days: 1))),
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(11),
color: baruTextutih,
),
),
],
),
),
],
),
],
),
),
Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(8)),
),
Container(
margin: EdgeInsets.only(
top: getProportionateScreenWidth(12),
left: getProportionateScreenWidth(8),
right: getProportionateScreenWidth(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Kursus",
style: primaryTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
letterSpacing: 0.5,
),
),
Column(
children: widget.dataHistoryTransactionModel.courses!
.map((course) =>
_listCourse(course.thumbnail, course.title))
.toList(),
),
],
),
),
Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10),
vertical: getProportionateScreenHeight(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (widget.dataHistoryTransactionModel.paymentDetail?.paymentType != 'qris') ...[
Row(
children: [
Text(
"Metode Pembayaran",
style: primaryTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(11),
),
),
Spacer(),
Text(
widget.dataHistoryTransactionModel.paymentDetail != null &&
bank.containsKey(widget.dataHistoryTransactionModel.paymentDetail!.bank)
? toBeginningOfSentenceCase(bank[widget.dataHistoryTransactionModel.paymentDetail!.bank] ?? '') ?? ''
: (store.containsKey(widget.dataHistoryTransactionModel.paymentDetail!.store)
? toBeginningOfSentenceCase(store[widget.dataHistoryTransactionModel.paymentDetail!.store] ?? '') ?? ''
: toBeginningOfSentenceCase(paymentType[widget.dataHistoryTransactionModel.paymentDetail!.paymentType] ?? '') ?? ''),
style: primaryTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
),
],
),
SizedBox(height: 8),
Row(
children: [
Text(
widget.dataHistoryTransactionModel.paymentDetail != null &&
bank.containsKey(widget.dataHistoryTransactionModel.paymentDetail!.bank)
? "Nomor Virtual Account"
: "Kode Pembayaran",
style: primaryTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(11),
),
),
Spacer(),
if (widget.dataHistoryTransactionModel.paymentDetail?.paymentType != 'qris')
Text(
widget.dataHistoryTransactionModel.paymentDetail != null
? widget.dataHistoryTransactionModel.paymentDetail!.vaNumber ?? 'QRIS'
: 'QRIS',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
],
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Total Pembayaran",
style: thirdTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(11),
),
),
Spacer(),
Text(
"Rp. ${widget.dataHistoryTransactionModel.totalPrice! < 50000 ? (widget.dataHistoryTransactionModel.totalPrice! + 5000) : widget.dataHistoryTransactionModel.totalPrice}",
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(13),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
DefaultButtonPayment(
height: 35,
width: 150,
press: () {
// Cek payment type, jika qris langsung arahkan ke SnapPaymentPage
if (widget.dataHistoryTransactionModel.paymentDetail?.paymentType == 'qris') {
var redirectUrl = widget.dataHistoryTransactionModel.token;
if (redirectUrl != null && redirectUrl.isNotEmpty) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SnapPaymentPage(
transactionToken: redirectUrl,
orderId: widget.dataHistoryTransactionModel.orderId ?? '',
grossAmount: widget.dataHistoryTransactionModel.totalPrice ?? 0,
courseTitle: '',
courseThumbnail: '',
courseInstructor: '',
courseId: '',
),
),
);
} else {
print("Pembayaran belum dimulai atau URL pembayaran tidak ada.");
}
} else {
selected.selectedTotalPrices = widget.dataHistoryTransactionModel.totalPrice ?? 0;
selectedInvoice.selectedThumbnail = widget.dataHistoryTransactionModel.courses![0].thumbnail;
Navigator.of(context).push(
CustomNavigator(
child: DetailInvoice(
orderId: widget.dataHistoryTransactionModel.orderId!,
dataHistoryTransactionModel: widget.dataHistoryTransactionModel,
),
),
);
}
},
text: "Bayar Sekarang",
weight: semiBold,
),
SizedBox(
width: getProportionateScreenWidth(150),
height: getProportionateScreenHeight(32),
child: TextButton(
onPressed: () async {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
elevation: 0.0,
backgroundColor:
Theme.of(context).colorScheme.background,
contentPadding: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(20),
horizontal: getProportionateScreenWidth(10),
),
actionsPadding: EdgeInsets.only(
right: getProportionateScreenWidth(10),
bottom: getProportionateScreenHeight(12),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
getProportionateScreenWidth(4)),
),
content: Text(
'Apakah Anda yakin ingin membatalkan transaksi?'),
actions: [
GestureDetector(
child: Text(
'Ya',
style: TextStyle(
color: primaryColor,
fontSize:
getProportionateScreenWidth(11),
),
),
onTap: () async {
Navigator.of(context).pop();
setState(() {
isLoading = true;
});
CancelPaymentService
cancelPaymentService =
CancelPaymentService();
String message =
await cancelPaymentService
.cancelPayment(widget
.dataHistoryTransactionModel
.orderId!);
widget.onPaymentCancelled(message);
setState(() {
isLoading = false;
});
},
),
SizedBox(
width: getProportionateScreenWidth(5)),
GestureDetector(
child: Text(
'Tidak',
style: TextStyle(
color: primaryColor,
fontSize:
getProportionateScreenWidth(11),
),
),
onTap: () {
Navigator.of(context).pop();
},
),
],
);
},
);
},
child: isLoading
? Container(
width: getProportionateScreenWidth(12),
height: getProportionateScreenHeight(10),
child: CircularProgressIndicator(
color: primaryColor,
),
)
: Text(
"Batalkan Transaksi",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: semiBold,
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
letterSpacing: 0.5,
),
),
style: TextButton.styleFrom(
foregroundColor:
Theme.of(context).colorScheme.background,
shape: RoundedRectangleBorder(
side: BorderSide(color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode),
borderRadius: BorderRadius.circular(
getProportionateScreenWidth(5),
),
),
backgroundColor: Colors.transparent,
),
),
),
],
),
SizedBox(height: 15),
widget.dataHistoryTransactionModel.statusPayment == 'Success' &&
widget.dataHistoryTransactionModel.paymentDetail!
.paymentType !=
'free'
? Column(
children: [
_customButton(text: 'Receipt'),
SizedBox(
height: getProportionateScreenHeight(10),
),
_customButton(text: 'Invoice'),
SizedBox(
height: getProportionateScreenHeight(20),
),
],
)
: widget.dataHistoryTransactionModel.statusPayment ==
'Pending'
? Padding(
padding: const EdgeInsets.only(top: 10, bottom: 15),
child: Column(
children: [
InkWell(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => widget
.dataHistoryTransactionModel
.paymentDetail!
.paymentType ==
'gopay'
? BatasBayarGopay()
: BatasBayar(
historyTransactionModel: widget
.dataHistoryTransactionModel,
)));
},
child: Container(
width: double.infinity,
padding: EdgeInsets.symmetric(vertical: 15),
child: Center(
child: Text(
'Detail Pembayaran',
style: thirdTextStyle.copyWith(
fontSize: 12, fontWeight: semiBold),
)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: primaryColor),
),
),
SizedBox(
height: 10,
),
InkWell(
onTap: () {
Provider.of<OrderProvider>(context,
listen: false)
.getTotalPrice(widget
.dataHistoryTransactionModel
.totalPrice
.toString());
Future.wait(widget
.dataHistoryTransactionModel.courses!
.map((course) async {
Provider.of<OrderProvider>(context,
listen: false)
.addOrder(
id: course.courseId,
discountPrice: course.price,
instructor: course.instructor,
price: course.price,
title: course.title,
imageUrl: '');
})).whenComplete(
() => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SnapPaymentPage(
orderId: widget
.dataHistoryTransactionModel
.orderId!,
grossAmount: widget
.dataHistoryTransactionModel
.totalPrice!, transactionToken: '', courseTitle: '', courseInstructor: '', courseThumbnail: '', courseId: '',
),
),
),
);
},
child: Container(
width: double.infinity,
padding: EdgeInsets.symmetric(vertical: 15),
child: Center(
child: Text(
'Ubah Metode Pembayaran',
style: thirdTextStyle.copyWith(
fontSize: 12,
fontWeight: semiBold,
color: primaryColor),
)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.transparent,
border:
Border.all(color: primaryColor)),
),
),
],
),
)
: Container()
],
),
),
],
),
);
}
}

View File

@ -0,0 +1,436 @@
import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/helper/validator.dart';
import 'package:initial_folder/providers/search_provider.dart';
import 'package:initial_folder/screens/detail_course/detail_course_screen.dart';
import 'package:initial_folder/screens/home/components/body_comp/product_card/product_card.dart';
import 'package:initial_folder/screens/search_course/component/filter.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
import 'package:initial_folder/widgets/search_not_found.dart';
import 'package:provider/provider.dart';
import '../providers/theme_provider.dart';
import '../size_config.dart';
import '../theme.dart';
import 'package:initial_folder/providers/filters_course_provider.dart'
as filterCourseProvider;
class SearchAndFilterCourse extends StatefulWidget {
const SearchAndFilterCourse({
Key? key,
}) : super(key: key);
static const routeName = '/search-and-filter';
@override
State<SearchAndFilterCourse> createState() => _SearchAndFilterCourseState();
}
class _SearchAndFilterCourseState extends State<SearchAndFilterCourse> {
final TextEditingController _controller = TextEditingController();
void clearTextField() {
_controller.clear();
}
@override
void initState() {
super.initState();
Provider.of<SearchProvider>(context, listen: false).resetState();
Provider.of<filterCourseProvider.FilterCourseProvider>(context,
listen: false)
.resetState();
Provider.of<filterCourseProvider.FilterCourseProvider>(context,
listen: false)
.resetFilter();
}
@override
Widget build(BuildContext context) {
final themeProvider = Provider.of<ThemeProvider>(context);
return Scaffold(
backgroundColor: Theme.of(context).colorScheme.background,
appBar: PreferredSize(
preferredSize: Size.fromHeight(getProportionateScreenWidth(57)),
child: AppBar(
scrolledUnderElevation: 0,
backgroundColor: Theme.of(context).colorScheme.background,
leadingWidth: 30,
actions: [
IconButton(
padding: EdgeInsets.zero,
onPressed: () => Navigator.of(context, rootNavigator: true).push(
CustomNavigator(
child: Filter(
onApplyFilter: clearTextField,
),
),
),
icon: Icon(
Icons.tune_rounded,
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
),
),
],
title: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Theme.of(context).brightness == Brightness.dark
? seventeenColor
: secondaryColor.withOpacity(0.3),
),
height: 40,
child: Consumer<SearchProvider>(
builder: (context, state, _) => TextField(
controller: _controller,
autofocus: false,
onSubmitted: (value) async {
Provider.of<filterCourseProvider.FilterCourseProvider>(
context,
listen: false)
.isSearchsFalse();
filterCourseProvider.FilterCourseProvider filterCourseProv =
Provider.of<filterCourseProvider.FilterCourseProvider>(
context,
listen: false);
state.searchTextFilter = "";
state.searchText = validatorSearch(value);
await state.initSearchCourse(
price: filterCourseProv.currentIndexPrice,
level: filterCourseProv.levels.join(','),
rating: filterCourseProv.currentIndexRating,
);
},
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
),
onChanged: (value) {
state.searchTextFilter = "";
state.searchText = validatorSearch(value);
},
cursorColor: secondaryColor,
decoration: InputDecoration(
border: InputBorder.none,
errorBorder: OutlineInputBorder(
borderSide: BorderSide(color: sevenColor),
borderRadius: BorderRadius.circular(10)),
contentPadding:
EdgeInsets.only(top: getProportionateScreenHeight(4)),
prefixIcon: Icon(
FeatherIcons.search,
size: 20,
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
),
hintText: 'Cari Kursus',
hintStyle: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color: secondaryColor,
letterSpacing: 0.5,
),
),
),
),
),
),
),
body: Provider.of<filterCourseProvider.FilterCourseProvider>(context)
.isSearch
? Consumer<filterCourseProvider.FilterCourseProvider>(
builder: (context, state, _) {
SearchProvider searchProvider =
Provider.of<SearchProvider>(context, listen: false);
print("Ini searchan ${searchProvider.search}");
if (state.state == filterCourseProvider.ResultState.loading) {
return Center(
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.green,
),
);
} else if (state.state ==
filterCourseProvider.ResultState.hasData) {
return Padding(
padding:
EdgeInsets.only(left: getProportionateScreenWidth(2)),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(14),
top: getProportionateScreenHeight(5),
),
child: Text(
"Kursus ${searchProvider.searchTextFilter.replaceAll('%', ' ')}",
textAlign: TextAlign.left,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontSize: getProportionateScreenWidth(15),
fontWeight: semiBold,
),
),
),
GridView.builder(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(20),
top: getProportionateScreenHeight(20),
bottom: getProportionateScreenHeight(20),
),
physics: ScrollPhysics(),
shrinkWrap: true,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 2.8 / 4,
crossAxisSpacing: 10,
mainAxisSpacing: 13,
),
itemCount: state.filterResult.length,
itemBuilder: (context, index) {
var course = state.filterResult[index];
int price = int.tryParse(
course.price.replaceAll('.', '')) ??
0;
int discountPrice = int.tryParse(course
.discountPrice
.replaceAll('.', '')) ??
0;
int calculatedPrice =
(course.discountPrice != '0')
? price - discountPrice
: price;
String displayedPrice = (calculatedPrice == 0)
? course.price
: calculatedPrice.toString();
return Container(
margin: EdgeInsets.only(
bottom: getProportionateScreenHeight(11)),
child: ProductCard(
totalDiscount: course.totalDiscount ?? 0,
students: course.students ?? '0',
id: course.idCourse,
thumbnail: course.thumbnail ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg',
title: course.title,
instructorName: course.instructorName,
specificRating: double.parse(
course.rating[0]!.avgRating != null
? '${course.rating[0]!.avgRating}'
: '5.0')
.toString(),
rating: course.rating[0]!.avgRating != null
? '${course.rating[0]!.avgRating}'
: '5.0',
numberOfRatings:
course.rating[0]!.totalReview ?? '0',
isTopCourse: course.topCourse ?? '0',
price: (course.price == '0')
? 'Gratis'
: (course.promoPrice != '0')
? numberFormat(course.promoPrice)
: numberFormat(displayedPrice),
realPrice: (course.price == '0')
? ''
: numberFormat(course.price),
press: () {
Navigator.of(context, rootNavigator: true)
.push(
CustomNavigator(
child: DetailCourseScreen(
idcourse: course.idCourse,
),
),
);
},
),
);
},
),
],
),
),
);
} else if (state.state ==
filterCourseProvider.ResultState.error ||
state.state == filterCourseProvider.ResultState.noData) {
return SearchNotFound();
} else {
return Center(child: Text(''));
}
},
)
: Consumer<SearchProvider>(
builder: (context, state, _) {
SearchProvider searchProvider =
Provider.of<SearchProvider>(context, listen: false);
if (state.state == ResultState.loading) {
return Center(
child: CircularProgressIndicator(
strokeWidth: 2,
color: primaryColor,
),
);
} else if (state.state == ResultState.hasData) {
return Padding(
padding:
EdgeInsets.only(left: getProportionateScreenWidth(2)),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(14),
top: getProportionateScreenHeight(5),
),
child: searchProvider.searchText.isNotEmpty
? Text(
"Kursus ${searchProvider.searchText.replaceAll('%', ' ')}",
textAlign: TextAlign.left,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontSize: getProportionateScreenWidth(15),
fontWeight: semiBold,
),
)
: Text(
"Kursus ${searchProvider.searchTextFilter.replaceAll('%', ' ')}",
textAlign: TextAlign.left,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontSize: getProportionateScreenWidth(15),
fontWeight: semiBold,
),
),
),
GridView.builder(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(20),
top: getProportionateScreenHeight(20),
bottom: getProportionateScreenHeight(20),
),
physics: ScrollPhysics(),
shrinkWrap: true,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 2.8 / 4,
crossAxisSpacing: 12,
mainAxisSpacing: 18,
),
itemCount: state.result.length,
itemBuilder: (context, index) {
var othersCourse = state.result[index];
int price = int.tryParse(
othersCourse.price.replaceAll('.', '')) ??
0;
int discountPrice = int.tryParse(othersCourse
.discountPrice
.replaceAll('.', '')) ??
0;
int calculatedPrice =
(othersCourse.discountPrice != '0')
? price - discountPrice
: price;
String displayedPrice = (calculatedPrice == 0)
? othersCourse.price.toString()
: calculatedPrice.toString();
return Container(
margin: EdgeInsets.only(
bottom: getProportionateScreenHeight(11)),
child: ProductCard(
totalDiscount:
othersCourse.totalDiscount ?? 0,
students: othersCourse.students ?? '0',
id: othersCourse.idCourse,
thumbnail: othersCourse.thumbnail ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg',
title: othersCourse.title,
instructorName: othersCourse.instructorName,
specificRating: (othersCourse
.rating.isNotEmpty &&
othersCourse.rating[0]?.avgRating !=
null)
? othersCourse.rating[0]!.avgRating
.toString()
: '0',
rating: (othersCourse.rating.isNotEmpty &&
othersCourse.rating[0]?.avgRating !=
null)
? othersCourse.rating[0]!.avgRating
.toString()
: '5.0',
numberOfRatings: (othersCourse
.rating.isNotEmpty &&
othersCourse.rating[0]?.totalReview !=
null)
? othersCourse.rating[0]!.totalReview!
: '0',
isTopCourse: othersCourse.topCourse ?? '0',
price: (othersCourse.price == '0')
? 'Gratis'
: (othersCourse.promoPrice != '0')
? numberFormat(
othersCourse.promoPrice)
: numberFormat(displayedPrice),
realPrice: (othersCourse.price == '0')
? ''
: numberFormat(
othersCourse.price.toString()),
press: () {
print('ini ke detail');
if (othersCourse.promoPrice != '0') {
Navigator.of(context, rootNavigator: true)
.push(
MaterialPageRoute(
builder: (context) =>
DetailCourseScreen(
isPromo: true,
idcourse: othersCourse.idCourse,
),
),
);
} else {
Navigator.of(context, rootNavigator: true)
.push(
MaterialPageRoute(
builder: (context) =>
DetailCourseScreen(
// isPromo: true,
idcourse: othersCourse.idCourse,
),
),
);
}
},
),
);
},
),
],
),
),
);
} else if (state.state == ResultState.noData ||
state.state == ResultState.error) {
return SearchNotFound();
} else {
return Center(child: Text(''));
}
},
),
);
}
}

View File

@ -0,0 +1,48 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/screens/home/components/body_comp/latest_course.dart';
import 'package:initial_folder/screens/home/components/body_comp/populer_course.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
class SearchNotFound extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: [
Center(
child: Container(
child: Image.asset(
color: Theme.of(context).brightness == Brightness.dark
? baruTextutih
: twelveColor,
'assets/images/kursuskosong.png',
width: getProportionateScreenHeight(100),
),
padding: EdgeInsets.only(top: 40, bottom: 16),
),
),
Text(
'Kursus Belum Tersedia',
style: secondaryTextStyle.copyWith(
fontSize: 14,
fontWeight: semiBold,
),
),
SizedBox(
height: 5,
),
Text(
'Kursus belum tersedia, silahkan cari kursus yang lain',
style: primaryTextStyle.copyWith(fontSize: 12, fontWeight: reguler),
),
SizedBox(
height: 25,
),
PopulerCourse(text: "Kursus Teratas"),
LatestCourse(text: "Kursus Terbaru"),
],
),
);
}
}

View File

@ -0,0 +1,73 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:initial_folder/theme.dart';
import 'package:webview_flutter/webview_flutter.dart';
class TermsAndCondition extends StatefulWidget {
static const routeName = '/article_web';
final String url;
final String? id;
const TermsAndCondition({Key? key, required this.url, this.id})
: super(key: key);
@override
State<TermsAndCondition> createState() => _TermsAndConditionState();
}
class _TermsAndConditionState extends State<TermsAndCondition> {
double progres = 0;
@override
Widget build(BuildContext context) {
final juduls = {
'sk': Text('Syarat dan Ketentuan'),
'prv': Text('Kebijakan Privasi'),
'about': Text('Tentang Vocasia'),
'ctc': Text('Kontak Kami'),
'help': Text('Bantuan'),
'gopay': Text('Gopay'),
};
final judul = juduls[widget.id];
var controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(const Color(0x00000000))
..setNavigationDelegate(
NavigationDelegate(
onProgress: (int progress) {
// Update loading bar.
},
onPageStarted: (String url) {},
onPageFinished: (String url) {},
onWebResourceError: (WebResourceError error) {},
onUrlChange: (change) {},
onNavigationRequest: (NavigationRequest request) {
if (request.url != widget.url) {
// Prevent navigation to other URLs and about:blank
print("Navigation prevented: ${request.url}");
return NavigationDecision.prevent;
} else {
print("Navigation Accesed: ${request.url}");
return NavigationDecision.navigate;
}
},
),
)
..loadRequest(Uri.parse(widget.url));
return Scaffold(
appBar: AppBar(title: judul),
body: Column(
children: [
LinearProgressIndicator(
value: progres,
color: sevenColor,
backgroundColor: secondaryColor,
),
Expanded(child: WebViewWidget(controller: controller)),
],
),
);
}
}

View File

@ -0,0 +1,87 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/helper/validator.dart';
import 'package:initial_folder/models/wishlist_model.dart';
import 'package:initial_folder/screens/detail_course/detail_course_screen.dart';
import 'package:initial_folder/screens/whislist/wishlist_card.dart';
class MyWishlistPage extends StatelessWidget {
const MyWishlistPage({Key? key, required this.wishlistDataModel})
: super(key: key);
final DataWihslistModel wishlistDataModel;
@override
Widget build(BuildContext context) {
return Container(
child: WishlistCard(
id: wishlistDataModel.wishlistId ?? '',
thumbnail: wishlistDataModel.thumbnail ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg',
title: wishlistDataModel.title ?? '',
numberOfRatings: wishlistDataModel.review[0].totalReview ?? '0',
press: () {
print(wishlistDataModel.courseId);
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => DetailCourseScreen(
// idcourse: wishlistDataModel.courseId ?? '0',
// ),
// ),
// );
},
price: (wishlistDataModel.discountPrice == '0')
? (wishlistDataModel.price == '0'
? 'Gratis'
: numberFormat(wishlistDataModel.price))
: numberFormat(wishlistDataModel.discountPrice),
isTopCourse: '0',
instructorName: wishlistDataModel.instructor ?? '',
rating: wishlistDataModel.review[0].avgRating != null
? '${wishlistDataModel.review[0].avgRating}'
: '5.0',
realPrice: (wishlistDataModel.discountPrice == '0')
? ''
: numberFormat(wishlistDataModel.price),
specificRating: double.parse(wishlistDataModel.review[0].avgRating != null
? '${wishlistDataModel.review[0].avgRating}'
: '0')
.toString(),
courseId: wishlistDataModel.courseId.toString(),
));
}
}
// return ProductCard(
// id: othersCourse.idCourse,
// thumbnail: othersCourse.thumbnail ??
// 'http://api.vocasia.pasia.id/uploads/courses_thumbnail/course_thumbnail_default_57.jpg',
// title: othersCourse.title,
// instructorName: othersCourse.instructorName,
// specificRating: double.parse(
// othersCourse.rating[0]!.avgRating != null
// ? '${othersCourse.rating[0]!.avgRating}'
// : '0')
// .toString(),
// rating: othersCourse.rating[0]!.avgRating != null
// ? '${othersCourse.rating[0]!.avgRating}'
// : '5.0',
// numberOfRatings: othersCourse.rating[0]!.totalReview ?? '0',
// isTopCourse: othersCourse.topCourse!,
// price: (othersCourse.discountPrice == '0')
// ? 'Gratis'
// : numberFormat(othersCourse.discountPrice),
// realPrice: (othersCourse.price == '0')
// ? ''
// : numberFormat(othersCourse.price),
// press: () {
// print(othersCourse.idCourse);
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => DetailCourseScreen(
// idcourse: othersCourse.idCourse,
// ),
// ),
// );
// },
// );