Compare commits

...

10 Commits

Author SHA1 Message Date
e6ce79528b Merge branch 'fix/level-list' into 'master'
feat: add replay functionality and improve error handling in audio player widget

See merge request profile-image/kedaireka/polinema-adapative-learning/mobile-adaptive-learning!31
2024-12-19 06:23:45 +00:00
2f1eef5f1a feat: add replay functionality and improve error handling in audio player widget 2024-12-19 13:21:55 +07:00
21e90e1b16 Merge branch 'fix/forgotPassword' into 'master'
chore: update and set minSdk to 24, and dispose emai controller in forgot password screen

See merge request profile-image/kedaireka/polinema-adapative-learning/mobile-adaptive-learning!30
2024-12-19 02:11:44 +00:00
9a357486a3 chore: update and set minSdk to 24, and dispose emai controller in forgot password screen 2024-12-19 09:10:22 +07:00
dfeb41cf79 Merge branch 'fix/responsive' into 'master'
refactor: adjust spacing and improve layout across multiple screens

See merge request profile-image/kedaireka/polinema-adapative-learning/mobile-adaptive-learning!29
2024-12-15 13:52:43 +00:00
Resh
aae59d0a86 refactor: adjust spacing and improve layout across multiple screens 2024-12-15 20:50:15 +07:00
bbd26c0cb1 Merge branch 'fix/gradle' into 'master'
chore: update Flutter and Gradle versions, and add FVM configuration

See merge request profile-image/kedaireka/polinema-adapative-learning/mobile-adaptive-learning!28
2024-12-14 11:24:56 +00:00
638c649ed9 chore: update Flutter and Gradle versions, and add FVM configuration 2024-12-14 18:23:42 +07:00
16778b14df Merge branch 'fix/section-review-logic' into 'master'
fix: section description dialog and review pretest exercise logic

See merge request profile-image/kedaireka/polinema-adapative-learning/mobile-adaptive-learning!27
2024-12-09 08:50:56 +00:00
Naresh Pratista
276d616bf0 fix: section description dialog and review pretest exercise logic 2024-12-09 15:49:09 +07:00
32 changed files with 551 additions and 381 deletions

3
.fvmrc Normal file
View File

@ -0,0 +1,3 @@
{
"flutter": "3.27.0-0.2.pre"
}

3
.gitignore vendored
View File

@ -44,3 +44,6 @@ app.*.map.json
/android/app/profile
/android/app/release
lib/core/services/constants.dart
# FVM Version Cache
.fvm/

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"dart.flutterSdkPath": ".fvm/versions/3.27.0-0.2.pre"
}

View File

@ -14,7 +14,7 @@ android {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8
}
@ -24,7 +24,7 @@ android {
applicationId = "com.example.english_learning"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
minSdk = 24
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName

View File

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip

View File

@ -18,7 +18,7 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.1.0" apply false
id "com.android.application" version "8.3.2" apply false
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
}

View File

@ -1,3 +1,3 @@
const String baseUrl = 'https://580d-36-85-62-81.ngrok-free.app/';
const String baseUrl = 'http://54.173.167.62/';
const String mediaUrl = 'https://580d-36-85-62-81.ngrok-free.app/api/uploads/';
const String mediaUrl = 'http://54.173.167.62/api/uploads/';

View File

@ -21,6 +21,9 @@ class CustomButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);
final screenWidth = mediaQuery.size.width;
return SizedBox(
width: width,
height: height,
@ -46,7 +49,7 @@ class CustomButton extends StatelessWidget {
text,
style: textStyle ??
AppTextStyles.blackButtonTextStyle.copyWith(
fontSize: 14,
fontSize: screenWidth * 0.036,
fontWeight: FontWeight.w900,
),
),

View File

@ -50,20 +50,23 @@ class CustomFieldWidget extends StatefulWidget {
class _CustomFieldWidgetState extends State<CustomFieldWidget> {
late TextEditingController _controller;
late ValidatorProvider _validatorProvider;
@override
void initState() {
super.initState();
_controller = widget.controller ?? TextEditingController();
context
.read<ValidatorProvider>()
.setController(widget.fieldName, _controller);
// Simpan referensi provider di initState
_validatorProvider = context.read<ValidatorProvider>();
_validatorProvider.setController(widget.fieldName, _controller);
}
@override
void dispose() {
context.read<ValidatorProvider>().removeController(widget.fieldName);
// Gunakan referensi yang disimpan sebelumnya
_validatorProvider.removeController(widget.fieldName);
if (widget.controller == null) {
_controller.dispose();
}

View File

@ -160,6 +160,7 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
),
],
),
SizedBox(height: screenHeight * 0.1)
],
);
}),
@ -168,4 +169,10 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
),
);
}
@override
void dispose() {
_emailController.dispose();
super.dispose();
}
}

View File

@ -19,8 +19,9 @@ class SigninScreen extends StatefulWidget {
}
class _SigninScreenState extends State<SigninScreen> {
final TextEditingController _loginController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
late TextEditingController _loginController = TextEditingController();
late TextEditingController _passwordController = TextEditingController();
late ValidatorProvider _validatorProvider;
final FocusNode _loginFocus = FocusNode();
final FocusNode _passwordFocus = FocusNode();
final _formKey = GlobalKey<FormState>();
@ -28,16 +29,22 @@ class _SigninScreenState extends State<SigninScreen> {
@override
void initState() {
super.initState();
context.read<ValidatorProvider>().setController('login', _loginController);
context
.read<ValidatorProvider>()
.setController('password', _passwordController);
_loginController = TextEditingController();
_passwordController = TextEditingController();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_validatorProvider = context.read<ValidatorProvider>();
_validatorProvider.setController('login', _loginController);
_validatorProvider.setController('password', _passwordController);
}
@override
void dispose() {
context.read<ValidatorProvider>().removeController('login');
context.read<ValidatorProvider>().removeController('password');
_validatorProvider.removeController('login');
_validatorProvider.removeController('password');
_loginController.dispose();
_passwordController.dispose();
@ -346,7 +353,7 @@ class _SigninScreenState extends State<SigninScreen> {
),
],
),
SizedBox(height: screenHeight * 0.02),
SizedBox(height: screenHeight * 0.1),
],
);
},

View File

@ -7,10 +7,10 @@ class LoginEmailField extends StatefulWidget {
const LoginEmailField({super.key});
@override
_LoginEmailFieldState createState() => _LoginEmailFieldState();
LoginEmailFieldState createState() => LoginEmailFieldState();
}
class _LoginEmailFieldState extends State<LoginEmailField> {
class LoginEmailFieldState extends State<LoginEmailField> {
late FocusNode _focusNode;
@override

View File

@ -316,6 +316,7 @@ class _SignupScreenState extends State<SignupScreen> {
),
],
),
SizedBox(height: screenHeight * 0.1)
],
);
},

View File

@ -67,14 +67,18 @@ class HistoryProvider with ChangeNotifier {
Future<void> fetchLearningHistory(String token) async {
if (_sectionProvider.sections.isEmpty) {
_error = 'No sections available';
notifyListeners();
WidgetsBinding.instance.addPostFrameCallback((_) {
notifyListeners();
});
return;
}
String sectionId = _sectionProvider.sections[_selectedPageIndex].id;
_isLoading = true;
_error = null;
notifyListeners();
WidgetsBinding.instance.addPostFrameCallback((_) {
notifyListeners();
});
try {
final history = await _repository.getLearningHistory(sectionId, token);
@ -85,7 +89,9 @@ class HistoryProvider with ChangeNotifier {
_historyModel = [];
} finally {
_isLoading = false;
notifyListeners();
WidgetsBinding.instance.addPostFrameCallback((_) {
notifyListeners();
});
}
}

View File

@ -361,6 +361,9 @@ class _HomeContentState extends State<HomeContent> {
@override
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);
final screenHeight = mediaQuery.size.height;
return RefreshIndicator(
onRefresh: _initializeData,
child: Consumer2<UserProvider, CompletedTopicsProvider>(
@ -486,7 +489,7 @@ class _HomeContentState extends State<HomeContent> {
return WelcomeCard(cardModel: cardData.cardData[index]);
},
options: CarouselOptions(
height: 168,
height: screenHeight * 0.19,
viewportFraction: 0.9,
enlargeCenterPage: true,
autoPlay: true,

View File

@ -69,7 +69,7 @@ class IncompleteSubmission extends StatelessWidget {
children: [
Expanded(
child: GlobalButton(
text: 'Check Again',
text: 'Check',
textColor: AppColors.blueColor,
borderColor: AppColors.blueColor,
backgroundColor: Colors.transparent,

View File

@ -1,6 +1,6 @@
import 'package:english_learning/core/services/repositories/level_repository.dart';
import 'package:english_learning/features/learning/modules/level/models/level_model.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
class LevelProvider with ChangeNotifier {
final LevelRepository _levelRepository = LevelRepository();
@ -21,8 +21,9 @@ class LevelProvider with ChangeNotifier {
Future<void> fetchLevels(String topicId, String token) async {
_isLoading = true;
_error = null;
notifyListeners();
WidgetsBinding.instance.addPostFrameCallback((_) {
notifyListeners();
});
try {
final result = await _levelRepository.getLevels(topicId, token);
_levels = result['levels'];
@ -37,7 +38,9 @@ class LevelProvider with ChangeNotifier {
_error = 'Error fetching levels: ${e.toString()}';
} finally {
_isLoading = false;
notifyListeners();
WidgetsBinding.instance.addPostFrameCallback((_) {
notifyListeners();
});
}
}
@ -48,7 +51,11 @@ class LevelProvider with ChangeNotifier {
bool isPretestFinished(String levelId) {
return _levels.any(
(level) => level.idLevel == levelId && level.idStudentLearning != null);
(level) =>
level.idLevel == levelId &&
level.idStudentLearning != null &&
level.score != null,
);
}
int getPretestScore(String levelId) {

View File

@ -20,13 +20,18 @@ class LevelCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);
final screenHeight = mediaQuery.size.height;
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 0,
child: Container(
height: MediaQuery.of(context).size.height * 0.6,
constraints: BoxConstraints(
maxHeight: screenHeight * 0.7,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
gradient: isAllowed
@ -107,20 +112,20 @@ class LevelCard extends StatelessWidget {
),
),
const SizedBox(height: 6),
// Score Display
Text(
// 'Score ${level.score}/100',
'Score $score/100',
style: AppTextStyles.whiteTextStyle.copyWith(
fontWeight: FontWeight.w900,
fontSize: 12,
),
),
const Spacer(), // Learn Now Button
const Spacer(),
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
),
child: CustomButton(
text: isAllowed ? 'Learn Now' : 'Locked',
textStyle:

View File

@ -24,12 +24,15 @@ class PretestCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);
final screenHeight = mediaQuery.size.height;
return Consumer<LevelProvider>(builder: (context, levelProvider, _) {
final isFinished = levelProvider.isPretestFinished(pretest.idLevel);
final score = levelProvider.getPretestScore(pretest.idLevel);
// final isAllowed = levelProvider.isLevelAllowed(pretest.idLevel);
void navigateToMaterial() {
if (isFinished) {
if (isFinished && pretest.score != null) {
// Mode review untuk pretest yang sudah selesai
Navigator.push(
context,
@ -80,7 +83,9 @@ class PretestCard extends StatelessWidget {
children: [
Container(
padding: const EdgeInsets.symmetric(
vertical: 4, horizontal: 8),
vertical: 4,
horizontal: 8,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color:
@ -125,7 +130,7 @@ class PretestCard extends StatelessWidget {
Flexible(
child: Image.asset(
'lib/features/learning/modules/level/assets/images/pretest_level_illustration.png',
height: 95,
height: screenHeight * 0.13,
fit: BoxFit.cover,
),
),
@ -133,8 +138,10 @@ class PretestCard extends StatelessWidget {
),
const SizedBox(height: 13),
CustomButton(
text: isFinished ? 'Review' : 'Learn Now',
textStyle: isFinished
text: isFinished && pretest.score != null
? 'Review'
: 'Learn Now',
textStyle: isFinished && pretest.score != null
? AppTextStyles.whiteTextStyle.copyWith(
fontWeight: FontWeight.w900,
)
@ -143,7 +150,9 @@ class PretestCard extends StatelessWidget {
),
width: double.infinity,
height: 36,
color: isFinished ? Colors.green : AppColors.yellowButtonColor,
color: isFinished && pretest.score != null
? Colors.green
: AppColors.yellowButtonColor,
onPressed: navigateToMaterial,
),
],

View File

@ -27,7 +27,6 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
Duration _position = Duration.zero;
bool _isAudioLoaded = false;
String? _errorMessage;
double _volume = 1.0;
bool _isDisposed = false;
@override
@ -88,6 +87,18 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
setState(() => _position = newPosition);
}
});
// Add completion listener
_audioPlayer.onPlayerComplete.listen((_) {
if (!_isDisposed) {
setState(() {
_position = Duration.zero;
_playerState = PlayerState.stopped;
});
// Reset source when playback completes
_audioPlayer.setSource(UrlSource(_getFullAudioUrl()));
}
});
}
String _getFullAudioUrl() {
@ -96,6 +107,20 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
: '${widget.baseUrl ?? ''}${widget.audioFileName}';
}
Future<void> _replayAudio() async {
try {
await _audioPlayer.seek(Duration.zero);
await _audioPlayer.setSource(UrlSource(_getFullAudioUrl()));
await _audioPlayer.resume();
} catch (error) {
if (!_isDisposed) {
setState(() {
_errorMessage = "Failed to replay audio: $error";
});
}
}
}
Widget _buildErrorWidget() {
return Container(
padding: const EdgeInsets.all(16),
@ -174,7 +199,7 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
),
),
const SizedBox(width: 12),
_buildVolumeButton(),
_buildReplayButton(),
],
),
if (_errorMessage != null)
@ -204,17 +229,36 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
size: 32,
),
onPressed: _isAudioLoaded
? () {
if (_playerState == PlayerState.playing) {
_audioPlayer.pause();
} else {
_audioPlayer.resume();
? () async {
try {
if (_playerState == PlayerState.playing) {
await _audioPlayer.pause();
} else {
await _audioPlayer.resume();
}
} catch (error) {
if (!_isDisposed) {
setState(() {
_errorMessage = "Failed to control playback: $error";
});
}
}
}
: null,
);
}
Widget _buildReplayButton() {
return IconButton(
icon: const Icon(
Icons.replay,
color: Colors.blue,
size: 24,
),
onPressed: _isAudioLoaded ? _replayAudio : null,
);
}
Widget _buildTimelineIndicator() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -243,9 +287,17 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
min: 0.0,
max: _duration.inSeconds.toDouble(),
onChanged: _isAudioLoaded
? (value) {
final position = Duration(seconds: value.toInt());
_audioPlayer.seek(position);
? (value) async {
try {
final position = Duration(seconds: value.toInt());
await _audioPlayer.seek(position);
} catch (error) {
if (!_isDisposed) {
setState(() {
_errorMessage = "Failed to seek: $error";
});
}
}
}
: null,
activeColor: Colors.blue,
@ -254,27 +306,6 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
);
}
Widget _buildVolumeButton() {
return IconButton(
icon: Icon(
_volume == 0.0 ? Icons.volume_off : Icons.volume_up,
color: _volume == 0.0 ? Colors.grey : Colors.blue,
size: 24,
),
onPressed: _isAudioLoaded
? () {
if (_volume == 0.0) {
_audioPlayer.setVolume(1.0);
setState(() => _volume = 1.0);
} else {
_audioPlayer.setVolume(0.0);
setState(() => _volume = 0.0);
}
}
: null,
);
}
@override
Widget build(BuildContext context) {
if (_errorMessage != null) {

View File

@ -1,5 +1,6 @@
import 'package:english_learning/core/services/constants.dart';
import 'package:english_learning/core/widgets/custom_snackbar.dart';
import 'package:english_learning/core/widgets/global_button.dart';
import 'package:english_learning/core/widgets/loading/shimmer_loading_widget.dart';
import 'package:english_learning/features/auth/provider/user_provider.dart';
import 'package:english_learning/features/learning/modules/level/screens/level_list_screen.dart';
@ -126,25 +127,10 @@ class _TopicsListScreenState extends State<TopicsListScreen> {
),
),
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),
),
padding: const EdgeInsets.all(32.0),
child: GlobalButton(
text: 'Close',
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,
),
),
),
),
],

View File

@ -5,22 +5,42 @@ import 'package:flutter/foundation.dart';
class SectionProvider extends ChangeNotifier {
final SectionRepository _repository = SectionRepository();
List<Section> _sections = [];
final bool _isLoading = false;
bool _isLoading = false;
dynamic _error;
List<Section> get sections => _sections;
bool get isLoading => _isLoading;
String? get error => _error;
Future<List<Section>> fetchSections(String token) async {
void resetData() {
_sections = [];
_error = null;
_isLoading = true;
notifyListeners();
}
Future<void> fetchSections(String token) async {
try {
// Set loading state
_isLoading = true;
_error = null;
notifyListeners();
// Fetch sections
_sections = await _repository.getSections(token);
// Reset loading state
_isLoading = false;
_error = null;
notifyListeners();
return _sections;
} catch (e) {
_error = e.toString();
// Handle error
_isLoading = false;
_error = e;
notifyListeners();
return [];
// Rethrow the error to be handled by the caller
rethrow;
}
}
}

View File

@ -24,7 +24,9 @@ class _LearningScreenState extends State<LearningScreen>
@override
void initState() {
super.initState();
_initializeSections();
WidgetsBinding.instance.addPostFrameCallback((_) {
_initializeSections();
});
}
Future<void> _initializeSections() async {
@ -32,45 +34,91 @@ class _LearningScreenState extends State<LearningScreen>
final sectionProvider =
Provider.of<SectionProvider>(context, listen: false);
// Cek apakah sections sudah ada
if (sectionProvider.sections.isEmpty) {
try {
final token = await userProvider.getValidToken();
if (token != null) {
await sectionProvider.fetchSections(token);
}
} catch (e) {
rethrow;
} finally {
setState(() {
_isInitialLoading = false;
});
try {
// Reset data sebelum fetch
sectionProvider.resetData(); // Tambahkan method ini di SectionProvider
final token = await userProvider.getValidToken();
if (token != null) {
await sectionProvider.fetchSections(token);
}
} else {
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Failed to load data: ${e.toString()}'),
action: SnackBarAction(
label: 'Retry',
onPressed: _initializeSections,
),
),
);
}
} finally {
setState(() {
_isInitialLoading = false;
});
}
}
Future<void> _refreshSections() async {
final userProvider = Provider.of<UserProvider>(context, listen: false);
final sectionProvider =
Provider.of<SectionProvider>(context, listen: false);
// Future<void> _refreshSections() async {
// final userProvider = Provider.of<UserProvider>(context, listen: false);
// final sectionProvider =
// Provider.of<SectionProvider>(context, listen: false);
try {
final token = await userProvider.getValidToken();
if (token != null) {
await sectionProvider.fetchSections(token);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Failed to refresh sections: $e'),
backgroundColor: Colors.red,
),
);
}
// try {
// final token = await userProvider.getValidToken();
// if (token != null) {
// await sectionProvider.fetchSections(token);
// }
// } catch (e) {
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: Text('Failed to refresh sections: $e'),
// backgroundColor: Colors.red,
// ),
// );
// }
// }
Widget _buildErrorWidget(String error) {
return Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.error_outline,
size: 48,
color: Colors.red[300],
),
const SizedBox(height: 16),
Text(
'Oops! Something went wrong',
style: AppTextStyles.blackTextStyle.copyWith(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
error,
textAlign: TextAlign.center,
style: AppTextStyles.disableTextStyle.copyWith(fontSize: 14),
),
const SizedBox(height: 16),
ElevatedButton.icon(
onPressed: _initializeSections,
icon: const Icon(Icons.refresh),
label: const Text('Retry'),
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryColor,
foregroundColor: Colors.white,
),
),
],
),
);
}
@override
@ -115,35 +163,13 @@ class _LearningScreenState extends State<LearningScreen>
// Tampilkan error jika ada
if (sectionProvider.error != null) {
return RefreshIndicator(
onRefresh: _refreshSections,
child: ListView(
children: [
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Error: ${sectionProvider.error}',
style: AppTextStyles.greyTextStyle,
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _refreshSections,
child: const Text('Retry'),
)
],
),
),
],
),
);
return _buildErrorWidget(sectionProvider.error!);
}
// Tampilkan sections atau pesan jika kosong
if (sectionProvider.sections.isEmpty) {
return RefreshIndicator(
onRefresh: _refreshSections,
onRefresh: _initializeSections,
child: ListView(
children: [
Center(
@ -165,7 +191,7 @@ class _LearningScreenState extends State<LearningScreen>
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _refreshSections,
onPressed: _initializeSections,
child: const Text('Refresh'),
)
],
@ -178,7 +204,7 @@ class _LearningScreenState extends State<LearningScreen>
// Tampilkan daftar sections
return RefreshIndicator(
onRefresh: _refreshSections,
onRefresh: _initializeSections,
child: ListView.builder(
itemCount: sectionProvider.sections.length,
itemBuilder: (context, index) {

View File

@ -107,7 +107,7 @@ class _OnBoardingScreenState extends State<OnBoardingScreen> {
currentPage: _currentPage,
itemCount: controller.onBoardingData.length,
),
SizedBox(height: screenHeight * 0.2),
SizedBox(height: screenHeight * 0.08),
if (_currentPage == controller.onBoardingData.length - 1)
Column(
children: [

View File

@ -51,92 +51,92 @@ class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
),
),
),
body: SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Consumer<ValidatorProvider>(
builder: (context, validatorProvider, child) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 22.0,
body: SingleChildScrollView(child: Consumer<ValidatorProvider>(
builder: (
context,
validatorProvider,
child,
) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 22.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CustomFieldWidget(
isRequired: true,
labelText: 'Old Password',
hintText: 'Enter your old password',
textInputAction: TextInputAction.next,
fieldName: 'Old Password',
obscureText: true,
controller: _oldPasswordController,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CustomFieldWidget(
isRequired: true,
labelText: 'Old Password',
hintText: 'Enter your old password',
textInputAction: TextInputAction.next,
fieldName: 'Old Password',
obscureText: true,
controller: _oldPasswordController,
),
const SizedBox(height: 12),
CustomFieldWidget(
isRequired: true,
labelText: 'New Password',
hintText: 'Enter your new password',
textInputAction: TextInputAction.next,
fieldName: 'new password',
obscureText: true,
controller: _newPasswordController,
),
const SizedBox(height: 12),
CustomFieldWidget(
isRequired: true,
labelText: 'Confirm New Password',
hintText: 'Retype your new password',
textInputAction: TextInputAction.next,
fieldName: 'confirm new password',
obscureText: true,
controller: _confirmPasswordController,
),
const SizedBox(height: 24),
GlobalButton(
text: 'Update Now',
onPressed: () async {
final userProvider =
Provider.of<UserProvider>(context, listen: false);
bool success = await userProvider.updatePassword(
oldPassword: _oldPasswordController.text,
newPassword: _newPasswordController.text,
confirmPassword: _confirmPasswordController.text,
);
const SizedBox(height: 12),
CustomFieldWidget(
isRequired: true,
labelText: 'New Password',
hintText: 'Enter your new password',
textInputAction: TextInputAction.next,
fieldName: 'new password',
obscureText: true,
controller: _newPasswordController,
),
const SizedBox(height: 12),
CustomFieldWidget(
isRequired: true,
labelText: 'Confirm New Password',
hintText: 'Retype your new password',
textInputAction: TextInputAction.next,
fieldName: 'confirm new password',
obscureText: true,
controller: _confirmPasswordController,
),
const SizedBox(height: 24),
GlobalButton(
text: 'Update Now',
onPressed: () async {
final userProvider =
Provider.of<UserProvider>(context, listen: false);
bool success = await userProvider.updatePassword(
oldPassword: _oldPasswordController.text,
newPassword: _newPasswordController.text,
confirmPassword: _confirmPasswordController.text,
);
if (success) {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return ChangePasswordDialog(
onSubmit: () {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) =>
const SigninScreen()),
(route) => false,
);
},
if (success) {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return ChangePasswordDialog(
onSubmit: () {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) => const SigninScreen()),
(route) => false,
);
},
);
} else {
CustomSnackBar.show(
context,
message:
'Failed to update password. Please try again.',
isError: true,
);
}
},
)
],
),
);
},
)),
},
);
} else {
CustomSnackBar.show(
context,
message: 'Failed to update password. Please try again.',
isError: true,
);
}
},
)
],
),
);
},
)),
);
}
}

View File

@ -89,6 +89,9 @@ class _EditProfileScreenState extends State<EditProfileScreen> {
@override
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);
final screenHeight = mediaQuery.size.height;
return Scaffold(
appBar: AppBar(
elevation: 0,
@ -196,6 +199,7 @@ class _EditProfileScreenState extends State<EditProfileScreen> {
],
),
),
SizedBox(height: screenHeight * 0.05),
],
));
}),

View File

@ -84,7 +84,7 @@ class LogoutConfirmation extends StatelessWidget {
const SizedBox(width: 10),
Expanded(
child: GlobalButton(
text: 'Yes, logout!',
text: 'Yes',
onPressed: onSubmit,
textColor: AppColors.whiteColor,
backgroundColor: AppColors.redColor,

View File

@ -25,6 +25,9 @@ class SettingsScreen extends StatefulWidget {
class _SettingsScreenState extends State<SettingsScreen> {
@override
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);
final screenHeight = mediaQuery.size.height;
final screenWidth = mediaQuery.size.width;
return Scaffold(
backgroundColor: AppColors.bgSoftColor,
body: Consumer<UserProvider>(builder: (context, userProvider, child) {
@ -35,7 +38,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
children: [
Container(
width: double.infinity,
height: 210,
height: screenHeight * 0.33,
decoration: BoxDecoration(
gradient: AppColors.gradientTheme,
borderRadius: const BorderRadius.only(
@ -44,8 +47,12 @@ class _SettingsScreenState extends State<SettingsScreen> {
),
),
child: Padding(
padding: const EdgeInsets.only(
top: 71.0, left: 26, right: 16.0, bottom: 19.0),
padding: EdgeInsets.only(
top: screenHeight * 0.1,
left: screenWidth * 0.07,
right: screenWidth * 0.04,
bottom: screenHeight * 0.03,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -54,7 +61,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
Row(
children: [
UserAvatar(
radius: 60,
radius: screenWidth * 0.15,
pictureUrl: userProvider.userData?['PICTURE'],
baseUrl: '${mediaUrl}avatar/',
onImageSelected: (File image) {
@ -63,7 +70,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
selectedImage: userProvider.selectedImage,
isLoading: userProvider.isLoading,
),
const SizedBox(width: 28),
const SizedBox(width: 16),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -72,7 +79,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
'Loading...',
style:
AppTextStyles.whiteTextStyle.copyWith(
fontSize: 18,
fontSize: screenWidth * 0.05,
fontWeight: FontWeight.bold,
),
),
@ -82,9 +89,11 @@ class _SettingsScreenState extends State<SettingsScreen> {
'Loading...',
style:
AppTextStyles.whiteTextStyle.copyWith(
fontSize: 14,
fontSize: screenWidth * 0.036,
fontWeight: FontWeight.w500,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
],
),

View File

@ -97,7 +97,7 @@ class WelcomeScreen extends StatelessWidget {
),
],
),
SizedBox(height: screenHeight * 0.1),
SizedBox(height: screenHeight * 0.05),
],
),
),

View File

@ -14,10 +14,11 @@ import just_audio
import package_info_plus
import path_provider_foundation
import shared_preferences_foundation
import sqflite
import sqflite_darwin
import url_launcher_macos
import video_player_avfoundation
import wakelock_plus
import webview_flutter_wkwebview
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
@ -33,4 +34,5 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))
FLTWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "FLTWebViewFlutterPlugin"))
}

View File

@ -5,34 +5,34 @@ packages:
dependency: transitive
description:
name: archive
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
sha256: "08064924cbf0ab88280a0c3f60db9dd24fec693927e725ecb176f16c629d1cb8"
url: "https://pub.dev"
source: hosted
version: "3.6.1"
version: "4.0.1"
args:
dependency: transitive
description:
name: args
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
url: "https://pub.dev"
source: hosted
version: "2.5.0"
version: "2.6.0"
async:
dependency: transitive
description:
name: async
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.12.0"
version: "2.11.0"
audio_session:
dependency: transitive
description:
name: audio_session
sha256: "343e83bc7809fbda2591a49e525d6b63213ade10c76f15813be9aed6657b3261"
sha256: b2a26ba8b7efa1790d6460e82971fde3e398cfbe2295df9dea22f3499d2c12a7
url: "https://pub.dev"
source: hosted
version: "0.1.21"
version: "0.1.23"
audioplayers:
dependency: "direct main"
description:
@ -93,10 +93,10 @@ packages:
dependency: transitive
description:
name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.1"
bootstrap_icons:
dependency: "direct main"
description:
@ -149,10 +149,10 @@ packages:
dependency: transitive
description:
name: charcode
sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306
sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a
url: "https://pub.dev"
source: hosted
version: "1.3.1"
version: "1.4.0"
checked_yaml:
dependency: transitive
description:
@ -181,10 +181,10 @@ packages:
dependency: transitive
description:
name: clock
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted
version: "1.1.2"
version: "1.1.1"
collection:
dependency: transitive
description:
@ -205,18 +205,18 @@ packages:
dependency: transitive
description:
name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
url: "https://pub.dev"
source: hosted
version: "3.0.3"
version: "3.0.6"
csslib:
dependency: transitive
description:
name: csslib
sha256: "831883fb353c8bdc1d71979e5b342c7d88acfbc643113c14ae51e2442ea0f20f"
sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e"
url: "https://pub.dev"
source: hosted
version: "0.17.3"
version: "1.0.2"
cupertino_icons:
dependency: "direct main"
description:
@ -253,42 +253,42 @@ packages:
dependency: transitive
description:
name: fake_async
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
url: "https://pub.dev"
source: hosted
version: "1.3.2"
version: "1.3.1"
ffi:
dependency: transitive
description:
name: ffi
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.3"
file:
dependency: transitive
description:
name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev"
source: hosted
version: "7.0.0"
version: "7.0.1"
file_selector_linux:
dependency: transitive
description:
name: file_selector_linux
sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492"
sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33"
url: "https://pub.dev"
source: hosted
version: "0.9.2+1"
version: "0.9.3+2"
file_selector_macos:
dependency: transitive
description:
name: file_selector_macos
sha256: f42eacb83b318e183b1ae24eead1373ab1334084404c8c16e0354f9a3e55d385
sha256: "271ab9986df0c135d45c3cdb6bd0faa5db6f4976d3e4b437cf7d0f258d941bfc"
url: "https://pub.dev"
source: hosted
version: "0.9.4"
version: "0.9.4+2"
file_selector_platform_interface:
dependency: transitive
description:
@ -301,18 +301,18 @@ packages:
dependency: transitive
description:
name: file_selector_windows
sha256: "2ad726953f6e8affbc4df8dc78b77c3b4a060967a291e528ef72ae846c60fb69"
sha256: "8f5d2f6590d51ecd9179ba39c64f722edc15226cc93dcc8698466ad36a4a85a4"
url: "https://pub.dev"
source: hosted
version: "0.9.3+2"
version: "0.9.3+3"
fixnum:
dependency: transitive
description:
name: fixnum
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
flick_video_player:
dependency: "direct main"
description:
@ -354,10 +354,10 @@ packages:
dependency: transitive
description:
name: flutter_inappwebview_internal_annotations
sha256: "5f80fd30e208ddded7dbbcd0d569e7995f9f63d45ea3f548d8dd4c0b473fb4c8"
sha256: "787171d43f8af67864740b6f04166c13190aa74a1468a1f1f1e9ee5b90c359cd"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.2.0"
flutter_inappwebview_ios:
dependency: transitive
description:
@ -402,10 +402,10 @@ packages:
dependency: "direct dev"
description:
name: flutter_launcher_icons
sha256: "619817c4b65b322b5104b6bb6dfe6cda62d9729bd7ad4303ecc8b4e690a67a77"
sha256: "31cd0885738e87c72d6f055564d37fabcdacee743b396b78c7636c169cac64f5"
url: "https://pub.dev"
source: hosted
version: "0.14.1"
version: "0.14.2"
flutter_lints:
dependency: "direct dev"
description:
@ -418,10 +418,10 @@ packages:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: "9ee02950848f61c4129af3d6ec84a1cfc0e47931abc746b03e7a3bc3e8ff6eda"
sha256: "9b78450b89f059e96c9ebb355fa6b3df1d6b330436e0b885fb49594c41721398"
url: "https://pub.dev"
source: hosted
version: "2.0.22"
version: "2.0.23"
flutter_secure_storage:
dependency: "direct main"
description:
@ -474,10 +474,10 @@ packages:
dependency: "direct main"
description:
name: flutter_svg
sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
sha256: "54900a1a1243f3c4a5506d853a2b5c2dbc38d5f27e52a52618a8054401431123"
url: "https://pub.dev"
source: hosted
version: "2.0.10+1"
version: "2.0.16"
flutter_test:
dependency: "direct dev"
description: flutter
@ -492,10 +492,10 @@ packages:
dependency: "direct main"
description:
name: flutter_widget_from_html
sha256: "9e2a6201c4d2eb910b6b3ebb2a9f5c490fc61c9a1aa35eafdde38f0fc659cf4c"
sha256: f3967a5b42896662efdd420b5adaf8a7d3692b0f44462a07c80e3b4c173b1a02
url: "https://pub.dev"
source: hosted
version: "0.15.2"
version: "0.15.3"
flutter_widget_from_html_core:
dependency: transitive
description:
@ -548,10 +548,10 @@ packages:
dependency: transitive
description:
name: fwfh_webview
sha256: f67890bc0d6278da98bd197469ae9511c859f7db327e92299fe0ea0cf46c4057
sha256: c0a8b664b642f40f4c252a0ab4e72c22dcd97c7fb3a7e50a6b4bdb6f63afca19
url: "https://pub.dev"
source: hosted
version: "0.15.2"
version: "0.15.3"
google_fonts:
dependency: "direct main"
description:
@ -564,18 +564,18 @@ packages:
dependency: "direct main"
description:
name: google_nav_bar
sha256: "1c8e3882fa66ee7b74c24320668276ca23affbd58f0b14a24c1e5590f4d07ab0"
sha256: bb12dd21514ee1b041ab3127673e2fd85e693337df308f7f2b75cd1e8e92eaf4
url: "https://pub.dev"
source: hosted
version: "5.0.6"
version: "5.0.7"
html:
dependency: "direct main"
description:
name: html
sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec"
url: "https://pub.dev"
source: hosted
version: "0.15.4"
version: "0.15.5"
http:
dependency: transitive
description:
@ -588,18 +588,18 @@ packages:
dependency: transitive
description:
name: http_parser
sha256: "40f592dd352890c3b60fec1b68e786cefb9603e05ff303dbc4dda49b304ecdf4"
sha256: "76d306a1c3afb33fe82e2bbacad62a61f409b5634c915fceb0d799de1a913360"
url: "https://pub.dev"
source: hosted
version: "4.1.0"
version: "4.1.1"
image:
dependency: transitive
description:
name: image
sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d
sha256: "599d08e369969bdf83138f5b4e0a7e823d3f992f23b8a64dd626877c37013533"
url: "https://pub.dev"
source: hosted
version: "4.3.0"
version: "4.4.0"
image_picker:
dependency: "direct main"
description:
@ -612,26 +612,26 @@ packages:
dependency: transitive
description:
name: image_picker_android
sha256: "8c5abf0dcc24fe6e8e0b4a5c0b51a5cf30cefdf6407a3213dae61edc75a70f56"
sha256: fa8141602fde3f7e2f81dbf043613eb44dfa325fa0bcf93c0f142c9f7a2c193e
url: "https://pub.dev"
source: hosted
version: "0.8.12+12"
version: "0.8.12+18"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
sha256: "65d94623e15372c5c51bebbcb820848d7bcb323836e12dfdba60b5d3a8b39e50"
sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.0.6"
image_picker_ios:
dependency: transitive
description:
name: image_picker_ios
sha256: "6703696ad49f5c3c8356d576d7ace84d1faf459afb07accbb0fae780753ff447"
sha256: "4f0568120c6fcc0aaa04511cb9f9f4d29fc3d0139884b1d06be88dcec7641d6b"
url: "https://pub.dev"
source: hosted
version: "0.8.12"
version: "0.8.12+1"
image_picker_linux:
dependency: transitive
description:
@ -724,18 +724,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
url: "https://pub.dev"
source: hosted
version: "10.0.8"
version: "10.0.7"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
url: "https://pub.dev"
source: hosted
version: "3.0.9"
version: "3.0.8"
leak_tracker_testing:
dependency: transitive
description:
@ -788,10 +788,10 @@ packages:
dependency: transitive
description:
name: mime
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev"
source: hosted
version: "1.0.6"
version: "2.0.0"
nested:
dependency: transitive
description:
@ -812,34 +812,34 @@ packages:
dependency: transitive
description:
name: package_info_plus
sha256: a75164ade98cb7d24cfd0a13c6408927c6b217fa60dee5a7ff5c116a58f28918
sha256: "70c421fe9d9cc1a9a7f3b05ae56befd469fe4f8daa3b484823141a55442d858d"
url: "https://pub.dev"
source: hosted
version: "8.0.2"
version: "8.1.2"
package_info_plus_platform_interface:
dependency: transitive
description:
name: package_info_plus_platform_interface
sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66
sha256: a5ef9986efc7bf772f2696183a3992615baa76c1ffb1189318dd8803778fb05b
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
path:
dependency: transitive
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
version: "1.9.0"
path_parsing:
dependency: transitive
description:
name: path_parsing
sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "1.1.0"
path_provider:
dependency: transitive
description:
@ -852,18 +852,18 @@ packages:
dependency: transitive
description:
name: path_provider_android
sha256: "490539678396d4c3c0b06efdaab75ae60675c3e0c66f72bc04c2e2c1e0e2abeb"
sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
url: "https://pub.dev"
source: hosted
version: "2.2.9"
version: "2.2.15"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.1"
path_provider_linux:
dependency: transitive
description:
@ -900,10 +900,10 @@ packages:
dependency: transitive
description:
name: platform
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.dev"
source: hosted
version: "3.1.5"
version: "3.1.6"
plugin_platform_interface:
dependency: transitive
description:
@ -912,6 +912,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.8"
posix:
dependency: transitive
description:
name: posix
sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a
url: "https://pub.dev"
source: hosted
version: "6.0.1"
provider:
dependency: "direct main"
description:
@ -932,26 +940,26 @@ packages:
dependency: "direct main"
description:
name: shared_preferences
sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051"
sha256: "95f9997ca1fb9799d494d0cb2a780fd7be075818d59f00c43832ed112b158a82"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.3.3"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e"
sha256: "02a7d8a9ef346c9af715811b01fbd8e27845ad2c41148eefd31321471b41863d"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.4.0"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
url: "https://pub.dev"
source: hosted
version: "2.5.2"
version: "2.5.4"
shared_preferences_linux:
dependency: transitive
description:
@ -1017,18 +1025,42 @@ packages:
dependency: transitive
description:
name: sqflite
sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d
sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
url: "https://pub.dev"
source: hosted
version: "2.3.3+1"
version: "2.4.1"
sqflite_android:
dependency: transitive
description:
name: sqflite_android
sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
sha256: "4058172e418eb7e7f2058dcb7657d451a8fc264afa0dea4dbd0f304a57131611"
sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
url: "https://pub.dev"
source: hosted
version: "2.5.4+3"
version: "2.5.4+6"
sqflite_darwin:
dependency: transitive
description:
name: sqflite_darwin
sha256: "96a698e2bc82bd770a4d6aab00b42396a7c63d9e33513a56945cbccb594c2474"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
sqflite_platform_interface:
dependency: transitive
description:
name: sqflite_platform_interface
sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
stack_trace:
dependency: transitive
description:
@ -1049,18 +1081,18 @@ packages:
dependency: transitive
description:
name: string_scanner
sha256: "0bd04f5bb74fcd6ff0606a888a30e917af9bd52820b178eaa464beb11dca84b6"
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
version: "1.3.0"
synchronized:
dependency: transitive
description:
name: synchronized
sha256: "51b08572b9f091f8c3eb4d9d4be253f196ff0075d5ec9b10a884026d5b55d7bc"
sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
url: "https://pub.dev"
source: hosted
version: "3.3.0+2"
version: "3.3.0+3"
term_glyph:
dependency: transitive
description:
@ -1081,10 +1113,10 @@ packages:
dependency: transitive
description:
name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
version: "1.3.2"
version: "1.4.0"
universal_html:
dependency: transitive
description:
@ -1113,34 +1145,34 @@ packages:
dependency: transitive
description:
name: url_launcher_android
sha256: f0c73347dfcfa5b3db8bc06e1502668265d39c08f310c29bff4e28eea9699f79
sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193"
url: "https://pub.dev"
source: hosted
version: "6.3.9"
version: "6.3.14"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e
sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626"
url: "https://pub.dev"
source: hosted
version: "6.3.1"
version: "6.3.2"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935"
url: "https://pub.dev"
source: hosted
version: "3.2.0"
version: "3.2.1"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672"
sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2"
url: "https://pub.dev"
source: hosted
version: "3.2.1"
version: "3.2.2"
url_launcher_platform_interface:
dependency: transitive
description:
@ -1169,34 +1201,34 @@ packages:
dependency: transitive
description:
name: uuid
sha256: f33d6bb662f0e4f79dcd7ada2e6170f3b3a2530c28fc41f49a411ddedd576a77
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
url: "https://pub.dev"
source: hosted
version: "4.5.0"
version: "4.5.1"
vector_graphics:
dependency: transitive
description:
name: vector_graphics
sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3"
sha256: "27d5fefe86fb9aace4a9f8375b56b3c292b64d8c04510df230f849850d912cb7"
url: "https://pub.dev"
source: hosted
version: "1.1.11+1"
version: "1.1.15"
vector_graphics_codec:
dependency: transitive
description:
name: vector_graphics_codec
sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da
sha256: "2430b973a4ca3c4dbc9999b62b8c719a160100dcbae5c819bae0cacce32c9cdb"
url: "https://pub.dev"
source: hosted
version: "1.1.11+1"
version: "1.1.12"
vector_graphics_compiler:
dependency: transitive
description:
name: vector_graphics_compiler
sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81"
sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad"
url: "https://pub.dev"
source: hosted
version: "1.1.11+1"
version: "1.1.16"
vector_math:
dependency: transitive
description:
@ -1209,50 +1241,50 @@ packages:
dependency: "direct main"
description:
name: video_player
sha256: e30df0d226c4ef82e2c150ebf6834b3522cf3f654d8e2f9419d376cdc071425d
sha256: "4a8c3492d734f7c39c2588a3206707a05ee80cef52e8c7f3b2078d430c84bc17"
url: "https://pub.dev"
source: hosted
version: "2.9.1"
version: "2.9.2"
video_player_android:
dependency: transitive
description:
name: video_player_android
sha256: e343701aa890b74a863fa460f5c0e628127ed06a975d7d9af6b697133fb25bdf
sha256: "391e092ba4abe2f93b3e625bd6b6a6ec7d7414279462c1c0ee42b5ab8d0a0898"
url: "https://pub.dev"
source: hosted
version: "2.7.1"
version: "2.7.16"
video_player_avfoundation:
dependency: transitive
description:
name: video_player_avfoundation
sha256: d1e9a824f2b324000dc8fb2dcb2a3285b6c1c7c487521c63306cc5b394f68a7c
sha256: "33224c19775fd244be2d6e3dbd8e1826ab162877bd61123bf71890772119a2b7"
url: "https://pub.dev"
source: hosted
version: "2.6.1"
version: "2.6.5"
video_player_platform_interface:
dependency: transitive
description:
name: video_player_platform_interface
sha256: "236454725fafcacf98f0f39af0d7c7ab2ce84762e3b63f2cbb3ef9a7e0550bc6"
sha256: "229d7642ccd9f3dc4aba169609dd6b5f3f443bb4cc15b82f7785fcada5af9bbb"
url: "https://pub.dev"
source: hosted
version: "6.2.2"
version: "6.2.3"
video_player_web:
dependency: transitive
description:
name: video_player_web
sha256: "6dcdd298136523eaf7dfc31abaf0dfba9aa8a8dbc96670e87e9d42b6f2caf774"
sha256: "881b375a934d8ebf868c7fb1423b2bfaa393a0a265fa3f733079a86536064a10"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.3.3"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
url: "https://pub.dev"
source: hosted
version: "14.3.1"
version: "14.3.0"
wakelock_plus:
dependency: transitive
description:
@ -1273,26 +1305,26 @@ packages:
dependency: transitive
description:
name: web
sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
url: "https://pub.dev"
source: hosted
version: "1.0.0"
version: "1.1.0"
webview_flutter:
dependency: transitive
description:
name: webview_flutter
sha256: "6869c8786d179f929144b4a1f86e09ac0eddfe475984951ea6c634774c16b522"
sha256: "889a0a678e7c793c308c68739996227c9661590605e70b1f6cf6b9a6634f7aec"
url: "https://pub.dev"
source: hosted
version: "4.8.0"
version: "4.10.0"
webview_flutter_android:
dependency: transitive
description:
name: webview_flutter_android
sha256: ed021f27ae621bc97a6019fb601ab16331a3db4bf8afa305e9f6689bdb3edced
sha256: "3d535126f7244871542b2f0b0fcf94629c9a14883250461f9abe1a6644c1c379"
url: "https://pub.dev"
source: hosted
version: "3.16.8"
version: "4.2.0"
webview_flutter_platform_interface:
dependency: transitive
description:
@ -1305,26 +1337,26 @@ packages:
dependency: transitive
description:
name: webview_flutter_wkwebview
sha256: "9c62cc46fa4f2d41e10ab81014c1de470a6c6f26051a2de32111b2ee55287feb"
sha256: b7e92f129482460951d96ef9a46b49db34bd2e1621685de26e9eaafd9674e7eb
url: "https://pub.dev"
source: hosted
version: "3.14.0"
version: "3.16.3"
win32:
dependency: transitive
description:
name: win32
sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a"
sha256: "8b338d4486ab3fbc0ba0db9f9b4f5239b6697fcee427939a40e720cbb9ee0a69"
url: "https://pub.dev"
source: hosted
version: "5.5.4"
version: "5.9.0"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://pub.dev"
source: hosted
version: "1.0.4"
version: "1.1.0"
xml:
dependency: transitive
description: