fix(refactor): description in topic list screen handling, and add various loading handling widget
This commit is contained in:
parent
e500ed0fa0
commit
b50ee898fe
|
|
@ -1 +1 @@
|
|||
const String baseUrl = 'https://7333-114-6-25-184.ngrok-free.app/';
|
||||
const String baseUrl = 'http://54.173.167.62/';
|
||||
|
|
|
|||
37
lib/core/widgets/loading/shimmer_loading_widget.dart
Normal file
37
lib/core/widgets/loading/shimmer_loading_widget.dart
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
|
||||
class ShimmerLoadingWidget extends StatelessWidget {
|
||||
final double width;
|
||||
final double height;
|
||||
final BorderRadius? borderRadius;
|
||||
final EdgeInsets? padding;
|
||||
|
||||
const ShimmerLoadingWidget({
|
||||
super.key,
|
||||
required this.width,
|
||||
required this.height,
|
||||
this.borderRadius,
|
||||
this.padding,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: padding ?? EdgeInsets.zero,
|
||||
child: Shimmer.fromColors(
|
||||
baseColor: Colors.grey[300]!,
|
||||
highlightColor: Colors.grey[100]!,
|
||||
period: const Duration(milliseconds: 1500),
|
||||
child: Container(
|
||||
width: width,
|
||||
height: height,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: borderRadius ?? BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import 'package:english_learning/features/history/screens/history_screen.dart';
|
|||
import 'package:english_learning/features/home/data/card_data.dart';
|
||||
import 'package:english_learning/features/home/provider/completed_topics_provider.dart';
|
||||
import 'package:english_learning/features/home/widgets/progress_card.dart';
|
||||
import 'package:english_learning/features/home/widgets/progress_card_loading.dart';
|
||||
import 'package:english_learning/features/home/widgets/welcome_card.dart';
|
||||
import 'package:english_learning/features/learning/screens/learning_screen.dart';
|
||||
import 'package:english_learning/features/settings/modules/edit_profile/screens/edit_profile_screen.dart';
|
||||
|
|
@ -17,7 +18,6 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:google_nav_bar/google_nav_bar.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
|
||||
class HomeScreen extends StatefulWidget {
|
||||
const HomeScreen({super.key});
|
||||
|
|
@ -203,31 +203,6 @@ class _HomeContentState extends State<HomeContent> {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildShimmerEffect() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
child: Shimmer.fromColors(
|
||||
baseColor: Colors.grey[300]!,
|
||||
highlightColor: Colors.grey[100]!,
|
||||
child: Column(
|
||||
children: List.generate(
|
||||
2,
|
||||
(index) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16.0),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 150,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
)),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCompletedTopicsContent(CompletedTopicsProvider provider) {
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
|
|
@ -438,7 +413,7 @@ class _HomeContentState extends State<HomeContent> {
|
|||
),
|
||||
),
|
||||
completedTopicsProvider.isLoading
|
||||
? _buildShimmerEffect()
|
||||
? const ProgressCardLoading()
|
||||
: completedTopicsProvider.completedTopics.isEmpty
|
||||
? _buildNoDataWidget()
|
||||
: _buildCompletedTopicsContent(
|
||||
|
|
|
|||
26
lib/features/home/widgets/progress_card_loading.dart
Normal file
26
lib/features/home/widgets/progress_card_loading.dart
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import 'package:english_learning/core/widgets/loading/shimmer_loading_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ProgressCardLoading extends StatelessWidget {
|
||||
const ProgressCardLoading({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
color: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
elevation: 0,
|
||||
margin: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: ShimmerLoadingWidget(
|
||||
width: double.infinity,
|
||||
height: 160,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import 'package:english_learning/features/learning/modules/level/screens/level_l
|
|||
import 'package:english_learning/features/learning/modules/topics/providers/topic_provider.dart';
|
||||
import 'package:english_learning/features/learning/modules/topics/widgets/topic_card.dart';
|
||||
import 'package:english_learning/core/utils/styles/theme.dart';
|
||||
import 'package:english_learning/features/learning/modules/topics/widgets/topic_card_loading.dart';
|
||||
import 'package:english_learning/features/learning/provider/section_provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
|
@ -53,6 +54,102 @@ class _TopicsListScreenState extends State<TopicsListScreen> {
|
|||
}
|
||||
}
|
||||
|
||||
// Tambahkan method baru di dalam _TopicsListScreenState
|
||||
void _showSectionDescriptionDialog(BuildContext context, String description) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
color: AppColors.whiteColor,
|
||||
shape: BoxShape.rectangle,
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Colors.black26,
|
||||
blurRadius: 10.0,
|
||||
offset: Offset(0.0, 10.0),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 16, horizontal: 16),
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColors.blueColor,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(16),
|
||||
topRight: Radius.circular(16),
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Section Description',
|
||||
style: AppTextStyles.whiteTextStyle.copyWith(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Content
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Text(
|
||||
description,
|
||||
style: AppTextStyles.greyTextStyle.copyWith(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w300,
|
||||
height: 1.5,
|
||||
),
|
||||
textAlign: TextAlign.justify,
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: ElevatedButton.icon(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColors.primaryColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 12, horizontal: 20),
|
||||
),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
icon: const Icon(Icons.close, color: Colors.white),
|
||||
label: const Text(
|
||||
'Close',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final sectionProvider = Provider.of<SectionProvider>(context);
|
||||
|
|
@ -71,6 +168,7 @@ class _TopicsListScreenState extends State<TopicsListScreen> {
|
|||
fontSize: 14,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
flexibleSpace: Container(
|
||||
decoration: BoxDecoration(
|
||||
|
|
@ -87,14 +185,13 @@ class _TopicsListScreenState extends State<TopicsListScreen> {
|
|||
_getFullImageUrl(selectedSection.thumbnail ?? ''),
|
||||
fit: BoxFit.cover,
|
||||
width: double.infinity,
|
||||
height: 115,
|
||||
height: 140,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
print('Error loading image: $error');
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
height: 115,
|
||||
height: 140,
|
||||
color: Colors.grey[300],
|
||||
child: Icon(
|
||||
child: const Icon(
|
||||
Icons.image_not_supported,
|
||||
color: Colors.grey,
|
||||
),
|
||||
|
|
@ -112,12 +209,18 @@ class _TopicsListScreenState extends State<TopicsListScreen> {
|
|||
),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 115,
|
||||
color: AppColors.blackColor.withOpacity(0.5),
|
||||
height: 140,
|
||||
color: AppColors.blackColor.withOpacity(0.7),
|
||||
),
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 42.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 32.0),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Text(
|
||||
selectedSection.description,
|
||||
style: AppTextStyles.whiteTextStyle.copyWith(
|
||||
|
|
@ -125,22 +228,82 @@ class _TopicsListScreenState extends State<TopicsListScreen> {
|
|||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
GestureDetector(
|
||||
onTap: () => _showSectionDescriptionDialog(
|
||||
context, selectedSection.description),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 8, horizontal: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.2),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
'Read More',
|
||||
style: AppTextStyles.whiteTextStyle.copyWith(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white.withOpacity(0.8),
|
||||
decoration: TextDecoration.underline,
|
||||
decorationColor: Colors.white.withOpacity(0.8),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// const SizedBox(height: 12),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Consumer<TopicProvider>(
|
||||
builder: (context, topicProvider, _) {
|
||||
if (topicProvider.isLoading) {
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
itemCount: 6,
|
||||
itemBuilder: (context, index) => const TopicCardLoading(),
|
||||
);
|
||||
}
|
||||
|
||||
if (topicProvider.error != null) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Failed to load topics',
|
||||
style: AppTextStyles.greyTextStyle,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
onPressed: _fetchTopics,
|
||||
child: const Text('Retry'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (topicProvider.topics.isEmpty) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (topicProvider.error != null) {
|
||||
return const Center(child: Text('No topics available'));
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
'No topics available',
|
||||
style: AppTextStyles.greyTextStyle,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: topicProvider.topics.length,
|
||||
itemBuilder: (context, index) {
|
||||
|
|
@ -163,7 +326,6 @@ class _TopicsListScreenState extends State<TopicsListScreen> {
|
|||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -6,12 +6,14 @@ class TopicCard extends StatelessWidget {
|
|||
final String description;
|
||||
final bool isCompleted;
|
||||
final VoidCallback? onTap;
|
||||
final bool isLoading;
|
||||
const TopicCard({
|
||||
super.key,
|
||||
this.onTap,
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.isCompleted,
|
||||
this.isLoading = false,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -52,7 +54,7 @@ class TopicCard extends StatelessWidget {
|
|||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
maxLines: 4,
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
|
|
@ -63,8 +65,7 @@ class TopicCard extends StatelessWidget {
|
|||
isCompleted
|
||||
? Icons.check_circle
|
||||
: Icons.radio_button_unchecked,
|
||||
color:
|
||||
isCompleted ? AppColors.blueColor : AppColors.greyColor,
|
||||
color: AppColors.blueColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
import 'package:english_learning/core/widgets/loading/shimmer_loading_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class TopicCardLoading extends StatelessWidget {
|
||||
const TopicCardLoading({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
color: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
elevation: 0,
|
||||
margin: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Title shimmer
|
||||
ShimmerLoadingWidget(
|
||||
width: double.infinity,
|
||||
height: 16,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// First line of description
|
||||
ShimmerLoadingWidget(
|
||||
width: double.infinity,
|
||||
height: 12,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
),
|
||||
// Second line of description (shorter)
|
||||
ShimmerLoadingWidget(
|
||||
width: MediaQuery.of(context).size.width * 0.6,
|
||||
height: 12,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
// Completion status icon shimmer
|
||||
ShimmerLoadingWidget(
|
||||
width: 24,
|
||||
height: 24,
|
||||
borderRadius: BorderRadius.circular(12), // Make it circular
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ import 'package:english_learning/features/auth/provider/user_provider.dart';
|
|||
import 'package:english_learning/features/learning/provider/section_provider.dart';
|
||||
import 'package:english_learning/features/learning/widgets/section_card.dart';
|
||||
import 'package:english_learning/features/learning/modules/topics/screens/topics_list_screen.dart';
|
||||
import 'package:english_learning/features/learning/widgets/section_card_shimmer.dart';
|
||||
import 'package:english_learning/features/learning/widgets/section_card_loading.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:english_learning/core/utils/styles/theme.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
|
@ -67,7 +67,12 @@ class _LearningScreenState extends State<LearningScreen> {
|
|||
child: Consumer<SectionProvider>(
|
||||
builder: (context, sectionProvider, _) {
|
||||
if (sectionProvider.isLoading) {
|
||||
return _buildShimmerLoading();
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
itemCount: 6,
|
||||
itemBuilder: (context, index) =>
|
||||
const SectionCardLoading(),
|
||||
);
|
||||
} else if (sectionProvider.error != null) {
|
||||
return Center(
|
||||
child: Column(
|
||||
|
|
@ -97,7 +102,7 @@ class _LearningScreenState extends State<LearningScreen> {
|
|||
itemCount: sectionProvider.sections.length,
|
||||
itemBuilder: (context, index) {
|
||||
final section = sectionProvider.sections[index];
|
||||
return LearningCard(
|
||||
return SectionCard(
|
||||
section: section,
|
||||
onTap: () => Navigator.push(
|
||||
context,
|
||||
|
|
@ -120,52 +125,4 @@ class _LearningScreenState extends State<LearningScreen> {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildShimmerLoading() {
|
||||
return ListView.builder(
|
||||
itemCount: 5, // Misalnya, kita menampilkan 5 shimmer items
|
||||
itemBuilder: (context, index) {
|
||||
return ShimmerWidget(
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(bottom: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 80,
|
||||
height: 80,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,24 @@
|
|||
import 'package:english_learning/core/services/constants.dart';
|
||||
import 'package:english_learning/core/widgets/loading/shimmer_loading_widget.dart';
|
||||
import 'package:english_learning/features/learning/modules/model/section_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:english_learning/core/utils/styles/theme.dart';
|
||||
|
||||
class LearningCard extends StatefulWidget {
|
||||
class SectionCard extends StatefulWidget {
|
||||
final Section section;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
const LearningCard({
|
||||
const SectionCard({
|
||||
super.key,
|
||||
required this.section,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
State<LearningCard> createState() => _LearningCardState();
|
||||
State<SectionCard> createState() => _SectionCardState();
|
||||
}
|
||||
|
||||
class _LearningCardState extends State<LearningCard>
|
||||
class _SectionCardState extends State<SectionCard>
|
||||
with SingleTickerProviderStateMixin {
|
||||
String _getFullImageUrl(String thumbnail) {
|
||||
if (thumbnail.startsWith('http')) {
|
||||
|
|
@ -64,11 +65,10 @@ class _LearningCardState extends State<LearningCard>
|
|||
},
|
||||
loadingBuilder: (context, child, loadingProgress) {
|
||||
if (loadingProgress == null) return child;
|
||||
return Container(
|
||||
return ShimmerLoadingWidget(
|
||||
width: 90,
|
||||
height: 104,
|
||||
color: Colors.grey[300],
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
);
|
||||
},
|
||||
)),
|
||||
|
|
|
|||
59
lib/features/learning/widgets/section_card_loading.dart
Normal file
59
lib/features/learning/widgets/section_card_loading.dart
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import 'package:english_learning/core/widgets/loading/shimmer_loading_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SectionCardLoading extends StatelessWidget {
|
||||
const SectionCardLoading({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
color: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
elevation: 1,
|
||||
margin: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ShimmerLoadingWidget(
|
||||
width: 90,
|
||||
height: 104,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Title shimmer
|
||||
ShimmerLoadingWidget(
|
||||
width: 200,
|
||||
height: 16,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
//description
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
for (int i = 0; i < 3; i++) ...[
|
||||
const ShimmerLoadingWidget(
|
||||
width: double.infinity,
|
||||
height: 12,
|
||||
borderRadius: BorderRadius.all(Radius.circular(4)),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
],
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
|
||||
class ShimmerWidget extends StatelessWidget {
|
||||
final Widget child;
|
||||
|
||||
const ShimmerWidget({
|
||||
super.key,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Shimmer.fromColors(
|
||||
baseColor: Colors.grey[300]!,
|
||||
highlightColor: Colors.grey[100]!,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user