Compare commits

..

No commits in common. "ee981ceba9150d39da7a8023dfd8d5c5c21bc497" and "76ce3853556845292b3f64eddf5a5e531e5cb269" have entirely different histories.

36 changed files with 546 additions and 1233 deletions

File diff suppressed because one or more lines are too long

View File

@ -52,7 +52,6 @@ import 'package:yimaru_app/services/audio_player_service.dart';
import 'package:yimaru_app/services/voice_recorder_service.dart'; import 'package:yimaru_app/services/voice_recorder_service.dart';
import 'package:yimaru_app/ui/views/course_practice_question/course_practice_question_view.dart'; import 'package:yimaru_app/ui/views/course_practice_question/course_practice_question_view.dart';
import 'package:yimaru_app/ui/views/learn_subcategory/learn_subcategory_view.dart'; import 'package:yimaru_app/ui/views/learn_subcategory/learn_subcategory_view.dart';
import 'package:yimaru_app/ui/views/learn_submodule/learn_submodule_view.dart';
// @stacked-import // @stacked-import
@StackedApp( @StackedApp(
@ -93,7 +92,6 @@ import 'package:yimaru_app/ui/views/learn_submodule/learn_submodule_view.dart';
MaterialRoute(page: CourseView), MaterialRoute(page: CourseView),
MaterialRoute(page: CoursePracticeQuestionView), MaterialRoute(page: CoursePracticeQuestionView),
MaterialRoute(page: LearnSubcategoryView), MaterialRoute(page: LearnSubcategoryView),
MaterialRoute(page: LearnSubmoduleView),
// @stacked-route // @stacked-route
], ],
dependencies: [ dependencies: [

File diff suppressed because it is too large Load Diff

View File

@ -1,52 +0,0 @@
import 'package:json_annotation/json_annotation.dart';
part 'lesson.g.dart';
@JsonSerializable()
class Lesson {
final int? id;
final String? title;
final String? thumbnail;
final String? description;
@JsonKey(name: 'is_active')
final bool? isActive;
@JsonKey(name: 'sub_module_id')
final int? subModuleId;
@JsonKey(name: 'teaching_text')
final String? teachingText;
@JsonKey(name: 'display_order')
final int? displayOrder;
@JsonKey(name: 'teaching_video_url')
final String? teachingVideoUrl;
@JsonKey(name: 'teaching_image_url')
final String? teachingImageUrl;
@JsonKey(name: 'teaching_audio_url')
final String? teachingAudioUrl;
const Lesson(
{this.id,
this.title,
this.isActive,
this.thumbnail,
this.subModuleId,
this.description,
this.teachingText,
this.displayOrder,
this.teachingAudioUrl,
this.teachingImageUrl,
this.teachingVideoUrl});
factory Lesson.fromJson(Map<String, dynamic> json) => _$LessonFromJson(json);
Map<String, dynamic> toJson() => _$LessonToJson(this);
}

View File

@ -1,35 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'lesson.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Lesson _$LessonFromJson(Map<String, dynamic> json) => Lesson(
id: (json['id'] as num?)?.toInt(),
title: json['title'] as String?,
isActive: json['is_active'] as bool?,
thumbnail: json['thumbnail'] as String?,
subModuleId: (json['sub_module_id'] as num?)?.toInt(),
description: json['description'] as String?,
teachingText: json['teaching_text'] as String?,
displayOrder: (json['display_order'] as num?)?.toInt(),
teachingAudioUrl: json['teaching_audio_url'] as String?,
teachingImageUrl: json['teaching_image_url'] as String?,
teachingVideoUrl: json['teaching_video_url'] as String?,
);
Map<String, dynamic> _$LessonToJson(Lesson instance) => <String, dynamic>{
'id': instance.id,
'title': instance.title,
'thumbnail': instance.thumbnail,
'description': instance.description,
'is_active': instance.isActive,
'sub_module_id': instance.subModuleId,
'teaching_text': instance.teachingText,
'display_order': instance.displayOrder,
'teaching_video_url': instance.teachingVideoUrl,
'teaching_image_url': instance.teachingImageUrl,
'teaching_audio_url': instance.teachingAudioUrl,
};

View File

@ -1,44 +0,0 @@
import 'package:json_annotation/json_annotation.dart';
part 'submodule.g.dart';
@JsonSerializable()
class Submodule {
final int? id;
final String? tips;
final String? title;
final String? thumbnail;
final String? description;
@JsonKey(name: 'module_id')
final int? moduleId;
@JsonKey(name: 'is_active')
final bool? isActive;
@JsonKey(name: 'display_order')
final int? displayOrder;
@JsonKey(name: 'legacy_sub_course_id')
final int? legacySubCourseId;
const Submodule(
{this.id,
this.title,
this.tips,
this.moduleId,
this.isActive,
this.thumbnail,
this.description,
this.displayOrder,
this.legacySubCourseId});
factory Submodule.fromJson(Map<String, dynamic> json) =>
_$SubmoduleFromJson(json);
Map<String, dynamic> toJson() => _$SubmoduleToJson(this);
}

View File

@ -1,31 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'submodule.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Submodule _$SubmoduleFromJson(Map<String, dynamic> json) => Submodule(
id: (json['id'] as num?)?.toInt(),
title: json['title'] as String?,
tips: json['tips'] as String?,
moduleId: (json['module_id'] as num?)?.toInt(),
isActive: json['is_active'] as bool?,
thumbnail: json['thumbnail'] as String?,
description: json['description'] as String?,
displayOrder: (json['display_order'] as num?)?.toInt(),
legacySubCourseId: (json['legacy_sub_course_id'] as num?)?.toInt(),
);
Map<String, dynamic> _$SubmoduleToJson(Submodule instance) => <String, dynamic>{
'id': instance.id,
'tips': instance.tips,
'title': instance.title,
'thumbnail': instance.thumbnail,
'description': instance.description,
'module_id': instance.moduleId,
'is_active': instance.isActive,
'display_order': instance.displayOrder,
'legacy_sub_course_id': instance.legacySubCourseId,
};

View File

@ -13,9 +13,7 @@ import 'package:yimaru_app/services/dio_service.dart';
import 'package:yimaru_app/ui/common/app_constants.dart'; import 'package:yimaru_app/ui/common/app_constants.dart';
import '../app/app.locator.dart'; import '../app/app.locator.dart';
import '../models/lesson.dart';
import '../models/module.dart'; import '../models/module.dart';
import '../models/submodule.dart';
import '../ui/common/enmus.dart'; import '../ui/common/enmus.dart';
class ApiService { class ApiService {
@ -676,52 +674,4 @@ class ApiService {
return []; return [];
} }
} }
// Get submodules
Future<List<Submodule>> getSubmodules(int id) async {
try {
List<Submodule> submodules = [];
final Response response = await _service.dio.get(
'$kBaseUrl/api/$kApiVersionUrl/$kCourseManagementUrl/$kModulesUrl/$id/$kSubmodulesUrl');
if (response.statusCode == 200) {
var data = response.data;
var decodedData = data['data']['sub_modules'] as List;
submodules = decodedData.map(
(e) {
return Submodule.fromJson(e);
},
).toList();
return submodules;
}
return [];
} catch (e) {
return [];
}
}
// Get lessons
Future<List<Lesson>> getLessons(int id) async {
try {
List<Lesson> lessons = [];
final Response response = await _service.dio.get(
'$kBaseUrl/api/$kApiVersionUrl/$kCourseManagementUrl/$kSubmodulesUrl/$id/$kLessonsUrl');
if (response.statusCode == 200) {
var data = response.data;
var decodedData = data['data'] as List;
lessons = decodedData.map(
(e) {
return Lesson.fromJson(e);
},
).toList();
return lessons;
}
return [];
} catch (e) {
return [];
}
}
} }

View File

@ -10,8 +10,6 @@ String kCoursesUrl = 'courses';
String kModulesUrl = 'modules'; String kModulesUrl = 'modules';
String kLessonsUrl = 'lessons';
String kRegisterUrl = 'register'; String kRegisterUrl = 'register';
String kCategoryUrl = 'categories'; String kCategoryUrl = 'categories';
@ -26,8 +24,6 @@ String kResendOtpUrl = 'resend-otp';
String kGetUserUrl = 'user-profile'; String kGetUserUrl = 'user-profile';
String kSubmodulesUrl = 'sub-modules';
String kSubcoursesUrl = 'sub-courses'; String kSubcoursesUrl = 'sub-courses';
String kCompleteLessonUrl = 'complete'; String kCompleteLessonUrl = 'complete';

View File

@ -28,7 +28,6 @@ enum StateObjects {
verifyOtp, verifyOtp,
resendOtp, resendOtp,
learnLevels, learnLevels,
learnLessons,
learnModules, learnModules,
learnCourses, learnCourses,
profileImage, profileImage,
@ -41,7 +40,6 @@ enum StateObjects {
loginWithGoogle, loginWithGoogle,
loadLessonVideo, loadLessonVideo,
loadCourseVideo, loadCourseVideo,
learnSubmodules,
requestResetCode, requestResetCode,
courseCategories, courseCategories,
profileCompletion, profileCompletion,

View File

@ -41,8 +41,9 @@ class CourseCategoryViewModel extends ReactiveViewModel {
// Remote api call // Remote api call
// Course categories // Course categories
Future<void> getCategories() async => await runBusyFuture(_getCategories(), Future<void> getCategories() async =>
busyObject: StateObjects.courseCategories); await runBusyFuture(_getCategories(),
busyObject: StateObjects.courseCategories);
Future<void> _getCategories() async { Future<void> _getCategories() async {
if (categories.isEmpty) { if (categories.isEmpty) {

View File

@ -66,7 +66,6 @@ class CourseLessonDetailViewModel extends BaseViewModel {
busyObject: StateObjects.loadCourseVideo); busyObject: StateObjects.loadCourseVideo);
Future<void> _initializePlayer(CourseLesson lesson) async { Future<void> _initializePlayer(CourseLesson lesson) async {
print('URL: $kSampleVideoUrl');
_videoPlayerController = _videoPlayerController =
VideoPlayerController.networkUrl(Uri.parse(kSampleVideoUrl)); VideoPlayerController.networkUrl(Uri.parse(kSampleVideoUrl));

View File

@ -1,30 +1,31 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:yimaru_app/models/submodule.dart';
import 'package:yimaru_app/ui/common/enmus.dart'; import 'package:yimaru_app/ui/common/enmus.dart';
import 'package:yimaru_app/ui/widgets/learn_lesson_tile.dart'; import 'package:yimaru_app/ui/widgets/learn_lesson_tile.dart';
import 'package:yimaru_app/ui/widgets/module_progress.dart'; import 'package:yimaru_app/ui/widgets/module_progress.dart';
import 'package:yimaru_app/ui/widgets/motivation_card.dart'; import 'package:yimaru_app/ui/widgets/motivation_card.dart';
import '../../../models/lesson.dart';
import '../../common/app_colors.dart'; import '../../common/app_colors.dart';
import '../../common/ui_helpers.dart'; import '../../common/ui_helpers.dart';
import '../../widgets/custom_circular_progress_indicator.dart'; import '../../widgets/custom_elevated_button.dart';
import '../../widgets/small_app_bar.dart'; import '../../widgets/small_app_bar.dart';
import 'learn_lesson_viewmodel.dart'; import 'learn_lesson_viewmodel.dart';
class LearnLessonView extends StackedView<LearnLessonViewModel> { class LearnLessonView extends StackedView<LearnLessonViewModel> {
final Submodule submodule; final String title;
final String topics;
const LearnLessonView({Key? key, required this.submodule}) : super(key: key); final String subtitle;
final String description;
final List<Map<String, dynamic>> practices;
@override
void onViewModelReady(LearnLessonViewModel viewModel) async {
await viewModel.getLessons(submodule.id ?? 0);
super.onViewModelReady(viewModel);
}
const LearnLessonView(
{Key? key,
required this.title,
required this.topics,
required this.subtitle,
required this.practices,
required this.description})
: super(key: key);
Widget getPadding(context) { Widget getPadding(context) {
double half = screenHeight(context) / 2; double half = screenHeight(context) / 2;
@ -116,63 +117,95 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
verticalSpaceTiny, verticalSpaceTiny,
_buildSubtitle(), _buildSubtitle(),
verticalSpaceSmall, verticalSpaceSmall,
_buildTopics(),
verticalSpaceSmall, verticalSpaceSmall,
_buildModuleProgress(), // _buildModuleProgress(),
verticalSpaceMedium, // verticalSpaceMedium,
verticalSpaceMedium, // _buildContinueButton(),
_buildMotivationCard(), // verticalSpaceMedium,
verticalSpaceMedium, // _buildMotivationCard(),
_buildHeader(), // verticalSpaceMedium,
verticalSpaceMedium, //_buildHeader(),
_buildListViewBuilder(viewModel), //verticalSpaceMedium,
// _buildListView(viewModel),
getPadding(context),
_buildStartButton(viewModel),
verticalSpaceSmall,
_buildPracticeButton(viewModel)
]; ];
Widget _buildTitle() => Text( Widget _buildTitle() => Text(
submodule.title ?? '', title,
style: style16DG600, style: style16DG600,
); );
Widget _buildSubtitle() => Text( Widget _buildSubtitle() => Text(
submodule.description ?? '', subtitle,
style: style14DG600, style: style14DG600,
); );
Widget _buildTopics() => Text(
topics,
style: style14DG500,
);
Widget _buildModuleProgress() => const ModuleProgress(); Widget _buildModuleProgress() => const ModuleProgress();
Widget _buildStartButton(LearnLessonViewModel viewModel) =>
CustomElevatedButton(
height: 55,
borderRadius: 12,
text: 'Start $title',
foregroundColor: kcWhite,
backgroundColor: kcPrimaryColor,
onTap: () async => await viewModel.navigateToLearnLessonDetail(
title: title, practices: practices, description: description),
);
Widget _buildPracticeButton(LearnLessonViewModel viewModel) =>
CustomElevatedButton(
height: 55,
borderRadius: 12,
text: 'Practice',
backgroundColor: kcWhite,
borderColor: kcPrimaryColor,
foregroundColor: kcPrimaryColor,
onTap: () async =>
await viewModel.navigateToLearnPractice(practices));
Widget _buildMotivationCard() => const MotivationCard(); Widget _buildMotivationCard() => const MotivationCard();
Widget _buildHeader() => Text( Widget _buildHeader() => Text(
'Lessons in this module', title,
style: style18DG700, style: style18DG700,
); );
Widget _buildListViewBuilder(LearnLessonViewModel viewModel) =>
viewModel.busy(StateObjects.learnLessons)
? _buildProgressIndicator()
: _buildListView(viewModel);
Widget _buildProgressIndicator() => const Center(
child: CustomCircularProgressIndicator(color: kcPrimaryColor),
);
Widget _buildListView(LearnLessonViewModel viewModel) => ListView.builder( Widget _buildListView(LearnLessonViewModel viewModel) => ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: viewModel.lessons.length, itemCount: viewModel.lessons.length,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => _buildTile( itemBuilder: (context, index) => _buildTile(
lesson: viewModel.lessons[index], title: viewModel.lessons[index]['title'],
onLessonTap: () async => await viewModel.navigateToLearnLessonDetail(viewModel.lessons[index]), status: viewModel.lessons[index]['status'],
thumbnail: viewModel.lessons[index]['thumbnail'],
onLessonTap: () async => await viewModel.navigateToLearnLessonDetail(
title: title, practices: practices, description: description),
// onPracticeTap: () async => await viewModel.navigateToLearnPractice(),
), ),
); );
Widget _buildTile({ Widget _buildTile({
required Lesson lesson, required String title,
required GestureTapCallback? onLessonTap, required String thumbnail,
GestureTapCallback? onLessonTap,
required ProgressStatuses status,
GestureTapCallback? onPracticeTap,
}) => }) =>
LearnLessonTile( LearnLessonTile(
lesson: lesson, title: title,
status: status,
thumbnail: thumbnail,
onLessonTap: onLessonTap, onLessonTap: onLessonTap,
onPracticeTap: onPracticeTap,
); );
} }

View File

@ -4,42 +4,47 @@ import 'package:yimaru_app/app/app.router.dart';
import 'package:yimaru_app/ui/common/enmus.dart'; import 'package:yimaru_app/ui/common/enmus.dart';
import '../../../app/app.locator.dart'; import '../../../app/app.locator.dart';
import '../../../models/lesson.dart';
import '../../../services/api_service.dart';
import '../../../services/status_checker_service.dart';
class LearnLessonViewModel extends BaseViewModel { class LearnLessonViewModel extends BaseViewModel {
// Dependency injection
final _apiService = locator<ApiService>();
final _statusChecker = locator<StatusCheckerService>();
final _navigationService = locator<NavigationService>(); final _navigationService = locator<NavigationService>();
// Learn lessons // Lessons
List<Lesson> _lessons = []; final List<Map<String, dynamic>> _lessons = [
{
'title': '1.1 Introducing Yourself',
'status': ProgressStatuses.completed,
'thumbnail': 'assets/images/image_1.png',
},
{
'status': ProgressStatuses.completed,
'thumbnail': 'assets/images/image_1.png',
'title': '1.2 Talking About Your Surroundings',
},
{
'status': ProgressStatuses.pending,
'title': '1.1 Introducing Yourself',
'thumbnail': 'assets/images/image_1.png',
},
];
List<Lesson> get lessons => _lessons; List<Map<String, dynamic>> get lessons => _lessons;
// Navigation // Navigation
void pop() => _navigationService.back(); void pop() => _navigationService.back();
Future<void> navigateToLearnLessonDetail(Lesson lesson) async => Future<void> navigateToLearnLessonDetail(
await _navigationService.navigateToLearnLessonDetailView(lesson: lesson); {required String title,
required List<Map<String, dynamic>> practices,
required String description}) async =>
await _navigationService.navigateToLearnLessonDetailView(
title: title, practices: practices, description: description);
// Remote api call Future<void> navigateToLearnPractice(
List<Map<String, dynamic>> practices) async =>
// Learn modules await _navigationService.navigateToLearnPracticeView(
Future<void> getLessons(int id) async => await runBusyFuture(_getLessons(id), practices: practices,
busyObject: StateObjects.learnLessons); title: 'Lets Practice',
buttonLabel: 'Begin Lesson Practice',
Future<void> _getLessons(int id) async { subtitle: 'Lets quickly review what youve learned in this lesson!',
if (_lessons.isEmpty) { );
if (await _statusChecker.checkConnection()) {
_lessons = await _apiService.getLessons(id);
_lessons.sort(
(a, b) => (a.displayOrder ?? 0).compareTo(b.displayOrder ?? 0));
}
}
}
} }

View File

@ -1,9 +1,8 @@
import 'package:chewie/chewie.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:vimeo_video_player/vimeo_video_player.dart';
import 'package:yimaru_app/ui/widgets/empty_video_player.dart'; import 'package:yimaru_app/ui/widgets/empty_video_player.dart';
import '../../../models/lesson.dart';
import '../../common/app_colors.dart'; import '../../common/app_colors.dart';
import '../../common/enmus.dart'; import '../../common/enmus.dart';
import '../../common/ui_helpers.dart'; import '../../common/ui_helpers.dart';
@ -12,14 +11,20 @@ import '../../widgets/small_app_bar.dart';
import 'learn_lesson_detail_viewmodel.dart'; import 'learn_lesson_detail_viewmodel.dart';
class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> { class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
final Lesson lesson; final String title;
final String description;
final List<Map<String, dynamic>> practices;
const LearnLessonDetailView({Key? key, required this.lesson}) const LearnLessonDetailView(
{Key? key,
required this.title,
required this.practices,
required this.description})
: super(key: key); : super(key: key);
Future<void> _navigate(LearnLessonDetailViewModel viewModel) async { Future<void> _navigate(LearnLessonDetailViewModel viewModel) async {
await viewModel.pause(); await viewModel.pause();
// await viewModel.navigateToLearnPractice(practices); await viewModel.navigateToLearnPractice(practices);
} }
@override @override
@ -29,6 +34,12 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
super.onDispose(viewModel); super.onDispose(viewModel);
} }
@override
void onViewModelReady(LearnLessonDetailViewModel viewModel) async {
await viewModel.initializePlayer();
super.onViewModelReady(viewModel);
}
@override @override
LearnLessonDetailViewModel viewModelBuilder(BuildContext context) => LearnLessonDetailViewModel viewModelBuilder(BuildContext context) =>
LearnLessonDetailViewModel(); LearnLessonDetailViewModel();
@ -114,7 +125,7 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
); );
Widget _buildTitle() => Text( Widget _buildTitle() => Text(
lesson.title ?? '', title,
style: style16DG600, style: style16DG600,
); );
@ -123,21 +134,21 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
height: 200, height: 200,
color: kcBlack, color: kcBlack,
width: double.maxFinite, width: double.maxFinite,
child: _buildVideoPlayer(viewModel), child: _buildVideoPlayerState(viewModel),
); );
Widget _buildVideoPlayerState(LearnLessonDetailViewModel viewModel) =>
viewModel.chewieController != null &&
viewModel.videoPlayerController != null &&
!viewModel.busy(StateObjects.loadLessonVideo)
? _buildVideoPlayer(viewModel)
: _buildEmptyVideoPlayer();
Widget _buildVideoPlayer(LearnLessonDetailViewModel viewModel) => Widget _buildVideoPlayer(LearnLessonDetailViewModel viewModel) =>
_buildVimeoPlayer(viewModel); _buildChewiePlayer(viewModel);
Widget _buildVimeoPlayer(LearnLessonDetailViewModel viewModel) => Widget _buildChewiePlayer(LearnLessonDetailViewModel viewModel) =>
VimeoVideoPlayer( Chewie(controller: viewModel.chewieController!);
isAutoPlay: true,
onInAppWebViewCreated: (controller) =>
viewModel.initializePlayer(controller),
videoId: lesson.teachingVideoUrl?.split('/').last ?? '',
);
Widget _buildEmptyVideoPlayer() => const EmptyVideoPlayer(); Widget _buildEmptyVideoPlayer() => const EmptyVideoPlayer();
@ -147,7 +158,7 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
); );
Widget _buildDescription() => Text( Widget _buildDescription() => Text(
lesson.description ?? '', description,
style: style14DG600, style: style14DG600,
); );
@ -164,7 +175,7 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
Widget _buildContinueButton(LearnLessonDetailViewModel viewModel) => Widget _buildContinueButton(LearnLessonDetailViewModel viewModel) =>
CustomElevatedButton( CustomElevatedButton(
height: 55, height: 55,
text: 'Lessons', text: 'Practice',
borderRadius: 12, borderRadius: 12,
foregroundColor: kcWhite, foregroundColor: kcWhite,
backgroundColor: kcPrimaryColor, backgroundColor: kcPrimaryColor,

View File

@ -1,10 +1,11 @@
import 'package:chewie/chewie.dart'; import 'package:chewie/chewie.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart'; import 'package:stacked_services/stacked_services.dart';
import 'package:video_player/video_player.dart'; import 'package:video_player/video_player.dart';
import 'package:yimaru_app/app/app.router.dart'; import 'package:yimaru_app/app/app.router.dart';
import 'package:yimaru_app/ui/common/app_constants.dart';
import 'package:yimaru_app/ui/common/enmus.dart'; import 'package:yimaru_app/ui/common/enmus.dart';
import 'package:yimaru_app/ui/common/ui_helpers.dart';
import '../../../app/app.locator.dart'; import '../../../app/app.locator.dart';
import '../../../services/status_checker_service.dart'; import '../../../services/status_checker_service.dart';
@ -19,10 +20,6 @@ class LearnLessonDetailViewModel extends BaseViewModel {
ChewieController? get chewieController => _chewieController; ChewieController? get chewieController => _chewieController;
InAppWebViewController? _webViewController;
InAppWebViewController? get webViewController => _webViewController;
VideoPlayerController? _videoPlayerController; VideoPlayerController? _videoPlayerController;
VideoPlayerController? get videoPlayerController => _videoPlayerController; VideoPlayerController? get videoPlayerController => _videoPlayerController;
@ -37,21 +34,31 @@ class LearnLessonDetailViewModel extends BaseViewModel {
await _chewieController?.pause(); await _chewieController?.pause();
} }
void initializePlayer(InAppWebViewController controller){ Future<void> initializePlayer() async =>
_webViewController = controller; await runBusyFuture(_initializePlayer(),
rebuildUi(); busyObject: StateObjects.loadLessonVideo);
}
void onLoadVideoStart() { Future<void> _initializePlayer() async {
setBusyForObject(StateObjects.loadLessonVideo, true); _videoPlayerController =
rebuildUi(); VideoPlayerController.networkUrl(Uri.parse(kSampleVideoUrl));
}
void onLoadVideoComplete() { await _videoPlayerController?.initialize();
setBusyForObject(StateObjects.loadLessonVideo, false);
rebuildUi();
}
if (_videoPlayerController != null) {
_chewieController = ChewieController(
looping: true,
autoPlay: true,
showOptions: true,
showControls: true,
aspectRatio: 16 / 9,
autoInitialize: true,
allowedScreenSleep: false,
videoPlayerController: _videoPlayerController!,
materialProgressColors: buildChewieProgressIndicator);
}
// rebuildUi();
}
// Navigation // Navigation
void pop() => _navigationService.back(); void pop() => _navigationService.back();

View File

@ -55,7 +55,6 @@ class LearnLevelView extends StackedView<LearnLevelViewModel> {
); );
Widget _buildAppBar(LearnLevelViewModel viewModel) => SmallAppBar( Widget _buildAppBar(LearnLevelViewModel viewModel) => SmallAppBar(
title: 'Levels',
onTap: viewModel.pop, onTap: viewModel.pop,
showBackButton: true, showBackButton: true,
); );
@ -83,8 +82,7 @@ class LearnLevelView extends StackedView<LearnLevelViewModel> {
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => _buildTile( itemBuilder: (context, index) => _buildTile(
level: viewModel.levels[index], level: viewModel.levels[index],
onTap: () async => onTap: () async => await viewModel.navigateToModule( viewModel.levels[index]),
await viewModel.navigateToModule(viewModel.levels[index]),
), ),
separatorBuilder: (context, index) => verticalSpaceSmall, separatorBuilder: (context, index) => verticalSpaceSmall,
); );

View File

@ -1,14 +1,13 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:yimaru_app/models/level.dart'; import 'package:yimaru_app/models/level.dart';
import 'package:yimaru_app/ui/common/enmus.dart';
import 'package:yimaru_app/ui/widgets/learn_module_tile.dart'; import 'package:yimaru_app/ui/widgets/learn_module_tile.dart';
import 'package:yimaru_app/ui/widgets/overall_learn_progress.dart'; import 'package:yimaru_app/ui/widgets/overall_learn_progress.dart';
import '../../../models/module.dart'; import '../../../models/module.dart';
import '../../common/app_colors.dart'; import '../../common/app_colors.dart';
import '../../common/enmus.dart';
import '../../common/ui_helpers.dart'; import '../../common/ui_helpers.dart';
import '../../widgets/custom_circular_progress_indicator.dart';
import '../../widgets/small_app_bar.dart'; import '../../widgets/small_app_bar.dart';
import 'learn_module_viewmodel.dart'; import 'learn_module_viewmodel.dart';
@ -58,7 +57,6 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
); );
Widget _buildAppBar(LearnModuleViewModel viewModel) => SmallAppBar( Widget _buildAppBar(LearnModuleViewModel viewModel) => SmallAppBar(
title: 'Modules',
onTap: viewModel.pop, onTap: viewModel.pop,
showBackButton: true, showBackButton: true,
); );
@ -81,10 +79,10 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
verticalSpaceMedium, verticalSpaceMedium,
_buildTitle(), _buildTitle(),
_buildSubtitle(), _buildSubtitle(),
verticalSpaceLarge, verticalSpaceMedium,
_buildOverallProgress(), _buildOverallProgress(),
verticalSpaceMedium, verticalSpaceMedium,
_buildListViewBuilder(viewModel) _buildListView(viewModel)
]; ];
Widget _buildTitle() => Text( Widget _buildTitle() => Text(
@ -97,36 +95,26 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
style: style14DG400, style: style14DG400,
); );
Widget _buildOverallProgress() => OverallLearnProgress( Widget _buildOverallProgress() => const OverallLearnProgress();
color: kcPrimaryColor.withOpacity(0.1),
);
Widget _buildListViewBuilder(LearnModuleViewModel viewModel) =>
viewModel.busy(StateObjects.learnModules)
? _buildProgressIndicator()
: _buildListView(viewModel);
Widget _buildProgressIndicator() => const Center(
child: CustomCircularProgressIndicator(color: kcPrimaryColor),
);
Widget _buildListView(LearnModuleViewModel viewModel) => ListView.builder( Widget _buildListView(LearnModuleViewModel viewModel) => ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: viewModel.modules.length, itemCount: viewModel.modules.length,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => _buildTile( itemBuilder: (context, index) => _buildTile(
module: viewModel.modules[index], module: viewModel.modules[index],
onModuleTap: () async => await viewModel onLessonTap: () {},
.navigateToLearnSubmodule(viewModel.modules[index]), onPracticeTap: () {}),
),
); );
Widget _buildTile({ Widget _buildTile({
required Module module, required Module module,
required GestureTapCallback onModuleTap, required GestureTapCallback onLessonTap,
required GestureTapCallback onPracticeTap,
}) => }) =>
LearnModuleTile( LearnModuleTile(
module: module, module: module,
onModuleTap: onModuleTap, onLessonTap: onLessonTap,
onPracticeTap: onPracticeTap,
); );
} }

View File

@ -24,8 +24,27 @@ class LearnModuleViewModel extends BaseViewModel {
// Navigation // Navigation
void pop() => _navigationService.back(); void pop() => _navigationService.back();
Future<void> navigateToLearnSubmodule(Module module) async => Future<void> navigateToLearnLesson(
await _navigationService.navigateToLearnSubmoduleView(module: module); {required String title,
required String topics,
required String subtitle,
required String description,
required List<Map<String, dynamic>> practices}) async =>
await _navigationService.navigateToLearnLessonView(
title: title,
topics: topics,
subtitle: subtitle,
practices: practices,
description: description);
Future<void> navigateToLearnPractice(
List<Map<String, dynamic>> practices) async =>
await _navigationService.navigateToLearnPracticeView(
practices: practices,
title: 'Lets Practice',
buttonLabel: 'Begin Lesson Practice',
subtitle: 'Lets quickly review what youve learned in this lesson!',
);
// Remote api call // Remote api call

View File

@ -1,146 +0,0 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import 'package:yimaru_app/models/module.dart';
import 'package:yimaru_app/models/submodule.dart';
import 'package:yimaru_app/ui/widgets/course_module_banner.dart';
import 'package:yimaru_app/ui/widgets/learn_submodule_tile.dart';
import '../../common/app_colors.dart';
import '../../common/enmus.dart';
import '../../common/ui_helpers.dart';
import '../../widgets/custom_circular_progress_indicator.dart';
import '../../widgets/custom_elevated_button.dart';
import '../../widgets/overall_learn_progress.dart';
import '../../widgets/small_app_bar.dart';
import 'learn_submodule_viewmodel.dart';
class LearnSubmoduleView extends StackedView<LearnSubmoduleViewModel> {
final Module module;
@override
void onViewModelReady(LearnSubmoduleViewModel viewModel) async {
await viewModel.getSubmodules(module.id ?? 0);
super.onViewModelReady(viewModel);
}
const LearnSubmoduleView({Key? key, required this.module}) : super(key: key);
@override
LearnSubmoduleViewModel viewModelBuilder(BuildContext context) =>
LearnSubmoduleViewModel();
@override
Widget builder(
BuildContext context,
LearnSubmoduleViewModel viewModel,
Widget? child,
) =>
_buildScaffoldWrapper(viewModel);
Widget _buildScaffoldWrapper(LearnSubmoduleViewModel viewModel) => Scaffold(
backgroundColor: kcBackgroundColor,
body: _buildScaffold(viewModel),
);
Widget _buildScaffold(LearnSubmoduleViewModel viewModel) =>
SafeArea(child: _buildBody(viewModel));
Widget _buildBody(LearnSubmoduleViewModel viewModel) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: _buildColumn(viewModel),
);
Widget _buildColumn(LearnSubmoduleViewModel viewModel) => Column(
children: [
verticalSpaceMedium,
_buildAppBar(viewModel),
verticalSpaceMedium,
_buildModulesColumnWrapper(viewModel),
],
);
Widget _buildAppBar(LearnSubmoduleViewModel viewModel) => SmallAppBar(
title: 'Submodules',
onTap: viewModel.pop,
showBackButton: true,
);
Widget _buildModulesColumnWrapper(LearnSubmoduleViewModel viewModel) =>
Expanded(child: _buildLevelsColumnScrollView(viewModel));
Widget _buildLevelsColumnScrollView(LearnSubmoduleViewModel viewModel) =>
SingleChildScrollView(
child: _buildLevelsColumn(viewModel),
);
Widget _buildLevelsColumn(LearnSubmoduleViewModel viewModel) => Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: _buildLevelsColumnChildren(viewModel),
);
List<Widget> _buildLevelsColumnChildren(LearnSubmoduleViewModel viewModel) =>
[
verticalSpaceMedium,
_buildTitle(),
verticalSpaceMedium,
_buildCourseModuleBanner(),
verticalSpaceMedium,
_buildOverallProgress(),
verticalSpaceTiny,
_buildContinueButton(viewModel),
verticalSpaceMedium,
_buildListViewBuilder(viewModel)
];
Widget _buildTitle() => Text(
module.title ?? '',
style: style18P600,
);
Widget _buildCourseModuleBanner() => const CourseModuleBanner();
Widget _buildOverallProgress() => const OverallLearnProgress(
color: Colors.transparent,
);
Widget _buildContinueButton(LearnSubmoduleViewModel viewModel) =>
const CustomElevatedButton(
height: 55,
borderRadius: 12,
foregroundColor: kcWhite,
text: 'Continue Submodule',
backgroundColor: kcPrimaryColor);
Widget _buildListViewBuilder(LearnSubmoduleViewModel viewModel) =>
viewModel.busy(StateObjects.learnSubmodules)
? _buildProgressIndicator()
: _buildListView(viewModel);
Widget _buildProgressIndicator() => const Center(
child: CustomCircularProgressIndicator(color: kcPrimaryColor),
);
Widget _buildListView(LearnSubmoduleViewModel viewModel) => ListView.builder(
shrinkWrap: true,
itemCount: viewModel.submodules.length,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => _buildTile(
submodule: viewModel.submodules[index],
onPracticeTap: () {},
onLessonTap: () async => await viewModel
.navigateToLearnLessons(viewModel.submodules[index]),
),
);
Widget _buildTile({
required Submodule submodule,
required GestureTapCallback onLessonTap,
required GestureTapCallback onPracticeTap,
}) =>
LearnSubmoduleTile(
submodule: submodule,
onLessonTap: onLessonTap,
onPracticeTap: onPracticeTap,
);
}

View File

@ -1,46 +0,0 @@
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import 'package:yimaru_app/app/app.router.dart';
import '../../../app/app.locator.dart';
import '../../../models/submodule.dart';
import '../../../services/api_service.dart';
import '../../../services/status_checker_service.dart';
import '../../common/enmus.dart';
class LearnSubmoduleViewModel extends BaseViewModel {
// Dependency injection
final _apiService = locator<ApiService>();
final _statusChecker = locator<StatusCheckerService>();
final _navigationService = locator<NavigationService>();
// Learn submodule
List<Submodule> _submodules = [];
List<Submodule> get submodules => _submodules;
// Navigation
void pop() => _navigationService.back();
Future<void> navigateToLearnLessons(Submodule submodule) async =>
await _navigationService.navigateToLearnLessonView(submodule: submodule);
// Remote api call
// Learn modules
Future<void> getSubmodules(int id) async =>
await runBusyFuture(_getSubmodules(id),
busyObject: StateObjects.learnSubmodules);
Future<void> _getSubmodules(int id) async {
if (_submodules.isEmpty) {
if (await _statusChecker.checkConnection()) {
_submodules = await _apiService.getSubmodules(id);
_submodules.sort(
(a, b) => (a.displayOrder ?? 0).compareTo(b.displayOrder ?? 0));
}
}
}
}

View File

@ -8,7 +8,7 @@ class CourseModuleBanner extends StatelessWidget {
Widget build(BuildContext context) => _buildContainer(); Widget build(BuildContext context) => _buildContainer();
Widget _buildContainer() => Container( Widget _buildContainer() => Container(
height: 125, height: 150,
width: double.maxFinite, width: double.maxFinite,
padding: const EdgeInsets.all(15), padding: const EdgeInsets.all(15),
decoration: BoxDecoration( decoration: BoxDecoration(

View File

@ -1,17 +1,27 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:yimaru_app/models/lesson.dart';
import 'package:yimaru_app/ui/widgets/mini_thumbnail.dart'; import 'package:yimaru_app/ui/widgets/mini_thumbnail.dart';
import '../common/app_colors.dart'; import '../common/app_colors.dart';
import '../common/enmus.dart';
import '../common/ui_helpers.dart'; import '../common/ui_helpers.dart';
import 'custom_elevated_button.dart'; import 'custom_elevated_button.dart';
import 'custom_linear_progress_indicator.dart'; import 'custom_linear_progress_indicator.dart';
class LearnLessonTile extends StatelessWidget { class LearnLessonTile extends StatelessWidget {
final Lesson lesson; final String title;
final String thumbnail;
final ProgressStatuses status;
final GestureTapCallback? onLessonTap; final GestureTapCallback? onLessonTap;
final GestureTapCallback? onPracticeTap;
const LearnLessonTile({super.key, this.onLessonTap, required this.lesson}); const LearnLessonTile({
super.key,
this.onLessonTap,
this.onPracticeTap,
required this.title,
required this.status,
required this.thumbnail,
});
@override @override
Widget build(BuildContext context) => _buildContainer(); Widget build(BuildContext context) => _buildContainer();
@ -22,55 +32,50 @@ class LearnLessonTile extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5), borderRadius: BorderRadius.circular(5),
border: Border.all( border: Border.all(
color: kcPrimaryColor.withOpacity(0.1), color: ProgressStatuses.pending == status
// color: ProgressStatuses.pending == status ? kcPrimaryColor.withOpacity(0.1)
// ? kcPrimaryColor.withOpacity(0.1) : kcGreen.withOpacity(0.1),
// : kcGreen.withOpacity(0.1),
), ),
), ),
child: _buildExpansionTile(), child: _buildExpansionTile(),
); );
Widget _buildExpansionTile() => ExpansionTile( Widget _buildExpansionTile() => ExpansionTile(
enabled: true,
title: _buildTitle(), title: _buildTitle(),
textColor: kcDarkGrey, textColor: kcDarkGrey,
showTrailingIcon: true, showTrailingIcon: true,
initiallyExpanded: true, trailing: _buildIconState(),
trailing: _buildPendingIcon(), // subtitle: _buildContent(),
collapsedIconColor: kcDarkGrey, collapsedIconColor: kcDarkGrey,
collapsedTextColor: kcDarkGrey, collapsedTextColor: kcDarkGrey,
leading: _buildLeadingWrapper(), leading: _buildLeadingWrapper(),
shape: Border.all(color: kcTransparent), shape: Border.all(color: kcTransparent),
expandedAlignment: Alignment.centerLeft, expandedAlignment: Alignment.centerLeft,
backgroundColor: kcGreen.withOpacity(0.1), enabled: status != ProgressStatuses.pending,
controlAffinity: ListTileControlAffinity.trailing, controlAffinity: ListTileControlAffinity.trailing,
expandedCrossAxisAlignment: CrossAxisAlignment.start, backgroundColor: ProgressStatuses.pending == status
collapsedBackgroundColor: kcPrimaryColor.withOpacity(0.1), ? kcPrimaryColor.withOpacity(0.1)
: kcGreen.withOpacity(0.1),
childrenPadding: const EdgeInsets.fromLTRB(15, 15, 15, 15), childrenPadding: const EdgeInsets.fromLTRB(15, 15, 15, 15),
expandedCrossAxisAlignment: CrossAxisAlignment.start,
collapsedBackgroundColor: ProgressStatuses.pending == status
? kcPrimaryColor.withOpacity(0.1)
: kcGreen.withOpacity(0.1),
tilePadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15), tilePadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
// enabled: status != ProgressStatuses.pending, initiallyExpanded: status != ProgressStatuses.completed ? true : false,
// backgroundColor: ProgressStatuses.pending == status
// ? kcPrimaryColor.withOpacity(0.1)
// : kcGreen.withOpacity(0.1),
// collapsedBackgroundColor: ProgressStatuses.pending == status
// ? kcPrimaryColor.withOpacity(0.1)
// : kcGreen.withOpacity(0.1),
// initiallyExpanded: status != ProgressStatuses.completed ? true : false,
children: _buildExpansionTileChildren(), children: _buildExpansionTileChildren(),
); );
Widget _buildLeadingWrapper() => Widget _buildLeadingWrapper() => MiniThumbnail(thumbnail: thumbnail);
MiniThumbnail(thumbnail: lesson.thumbnail ?? 'assets/images/image_1.png');
Widget _buildTitle() => Text( Widget _buildTitle() => Text(
lesson.title ?? '', title,
style: style16DG600, style: style16DG600,
); );
// Widget _buildIconState() => ProgressStatuses.pending == status Widget _buildIconState() => ProgressStatuses.pending == status
// ? _buildPendingIcon() ? _buildPendingIcon()
// : _buildCompleteIcon(); : _buildCompleteIcon();
Widget _buildCompleteIcon() => const Icon( Widget _buildCompleteIcon() => const Icon(
Icons.check, Icons.check,
@ -93,35 +98,58 @@ class LearnLessonTile extends StatelessWidget {
List<Widget> _buildExpansionTileItemChildren() => [ List<Widget> _buildExpansionTileItemChildren() => [
_buildProgress(), _buildProgress(),
horizontalSpaceSmall, horizontalSpaceSmall,
// _buildProgressText(), _buildProgressText(),
// verticalSpaceSmall, verticalSpaceSmall,
_buildActionButtonWrapper() _buildActionButtonWrapper()
]; ];
Widget _buildProgress() => const CustomLinearProgressIndicator( Widget _buildProgress() => CustomLinearProgressIndicator(
progress: 0,
activeColor: kcPrimaryColor, activeColor: kcPrimaryColor,
backgroundColor: kcVeryLightGrey, backgroundColor: kcVeryLightGrey,
progress: ProgressStatuses.completed == status ? 1 : 0.75,
); );
// Widget _buildProgressText() => Text( Widget _buildProgressText() => Text(
// ProgressStatuses.completed == status ? 'Completed' : 'In Progress', ProgressStatuses.completed == status ? 'Completed' : 'In Progress',
// style: style14P400, style: style14P400,
// ); );
Widget _buildActionButtonWrapper() => SizedBox( Widget _buildActionButtonWrapper() => SizedBox(
height: 50, height: 40,
child: _buildLessonButton(), child: _buildActionButtons(),
);
Widget _buildActionButtons() => Row(
mainAxisAlignment: MainAxisAlignment.end,
children: _buildActionButtonChildren(),
);
List<Widget> _buildActionButtonChildren() => [
_buildPracticeButton(),
horizontalSpaceSmall,
_buildLessonButton(),
];
Widget _buildPracticeButton() => CustomElevatedButton(
height: 15,
width: 135,
text: 'Practice',
borderRadius: 12,
onTap: onPracticeTap,
trailingIcon: Icons.mic,
backgroundColor: kcWhite,
borderColor: kcPrimaryColor,
foregroundColor: kcPrimaryColor,
); );
Widget _buildLessonButton() => CustomElevatedButton( Widget _buildLessonButton() => CustomElevatedButton(
height: 15, height: 15,
text: 'Start', width: 135,
borderRadius: 12, borderRadius: 12,
onTap: onLessonTap, onTap: onLessonTap,
width: double.maxFinite,
foregroundColor: kcWhite, foregroundColor: kcWhite,
trailingIcon: Icons.play_arrow, trailingIcon: Icons.play_arrow,
backgroundColor: kcPrimaryColor, backgroundColor: kcPrimaryColor,
text: ProgressStatuses.completed == status ? 'View' : 'Continue',
); );
} }

View File

@ -6,14 +6,17 @@ import 'package:yimaru_app/ui/widgets/finish_practice_sheet.dart';
import '../../models/module.dart'; import '../../models/module.dart';
import '../common/app_colors.dart'; import '../common/app_colors.dart';
import '../common/enmus.dart';
import '../common/ui_helpers.dart'; import '../common/ui_helpers.dart';
import 'custom_elevated_button.dart'; import 'custom_elevated_button.dart';
class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> { class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
final Module module; final Module module;
final GestureTapCallback? onModuleTap; final GestureTapCallback? onLessonTap;
final GestureTapCallback? onPracticeTap;
const LearnModuleTile({super.key, this.onModuleTap, required this.module}); const LearnModuleTile(
{super.key, this.onLessonTap, this.onPracticeTap, required this.module});
Future<void> _showSheet( Future<void> _showSheet(
{required BuildContext context, {required BuildContext context,
@ -155,7 +158,7 @@ class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
required LearnModuleViewModel viewModel}) => required LearnModuleViewModel viewModel}) =>
SizedBox( SizedBox(
height: 40, height: 40,
child: _buildModuleButton(viewModel), child: _buildActionButtons(context: context, viewModel: viewModel),
); );
Widget _buildActionButtons( Widget _buildActionButtons(
@ -163,39 +166,46 @@ class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
required LearnModuleViewModel viewModel}) => required LearnModuleViewModel viewModel}) =>
Row( Row(
children: [ children: [
_buildModuleButtonWrapper(viewModel), _buildLessonButtonWrapper(viewModel),
horizontalSpaceSmall, horizontalSpaceSmall,
_buildPracticeButtonWrapper(context: context, viewModel: viewModel) _buildPracticeButtonWrapper(context: context, viewModel: viewModel)
], ],
); );
Widget _buildModuleButtonWrapper(LearnModuleViewModel viewModel) => Expanded( Widget _buildLessonButtonWrapper(LearnModuleViewModel viewModel) => Expanded(
child: _buildModuleButton(viewModel), child: _buildLessonButton(viewModel),
); );
Widget _buildModuleButton(LearnModuleViewModel viewModel) => Widget _buildLessonButton(LearnModuleViewModel viewModel) =>
CustomElevatedButton( CustomElevatedButton(
height: 15, height: 15,
borderRadius: 12, borderRadius: 12,
onTap: onModuleTap, onTap: onLessonTap,
text: 'View Module', text: 'View Module',
foregroundColor: kcWhite, foregroundColor: kcWhite,
backgroundColor: kcPrimaryColor, backgroundColor: kcPrimaryColor,
// onTap: () async => await viewModel.navigateToLearnLesson(
// title: title,
// topics: topics,
// subtitle: subtitle,
// practices: practices,
// description: description),
); );
Widget _buildPracticeButtonWrapper( Widget _buildPracticeButtonWrapper(
{required BuildContext context, {required BuildContext context,
required LearnModuleViewModel viewModel}) => required LearnModuleViewModel viewModel}) =>
Expanded( Expanded(
child: Container(), child: _buildPracticeButton(context: context, viewModel: viewModel),
); );
Widget _buildPracticeButton( Widget _buildPracticeButton(
{required BuildContext context, {required BuildContext context,
required LearnModuleViewModel viewModel}) => required LearnModuleViewModel viewModel}) =>
const CustomElevatedButton( CustomElevatedButton(
height: 15, height: 15,
borderRadius: 12, borderRadius: 12,
onTap: onPracticeTap,
text: 'View Practices', text: 'View Practices',
backgroundColor: kcWhite, backgroundColor: kcWhite,
borderColor: kcPrimaryColor, borderColor: kcPrimaryColor,

View File

@ -1,237 +0,0 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import 'package:yimaru_app/models/submodule.dart';
import 'package:yimaru_app/ui/widgets/custom_linear_progress_indicator.dart';
import 'package:yimaru_app/ui/widgets/finish_practice_sheet.dart';
import '../common/app_colors.dart';
import '../common/ui_helpers.dart';
import '../views/learn_submodule/learn_submodule_viewmodel.dart';
import 'custom_elevated_button.dart';
class LearnSubmoduleTile extends ViewModelWidget<LearnSubmoduleViewModel> {
final Submodule submodule;
final GestureTapCallback? onLessonTap;
final GestureTapCallback? onPracticeTap;
const LearnSubmoduleTile(
{super.key,
this.onLessonTap,
this.onPracticeTap,
required this.submodule});
Future<void> _showSheet(
{required BuildContext context,
required LearnSubmoduleViewModel viewModel}) async =>
await showModalBottomSheet(
context: context,
backgroundColor: kcTransparent,
builder: (_) => _buildSheet(viewModel),
);
@override
Widget build(BuildContext context, LearnSubmoduleViewModel viewModel) =>
_buildExpansionTileCard(context: context, viewModel: viewModel);
Widget _buildExpansionTileCard(
{required BuildContext context,
required LearnSubmoduleViewModel viewModel}) =>
Container(
margin: const EdgeInsets.only(bottom: 15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(color: kcVeryLightGrey),
),
child: _buildTileStack(context: context, viewModel: viewModel),
);
Widget _buildTileStack(
{required BuildContext context,
required LearnSubmoduleViewModel viewModel}) =>
Stack(
children: [
_buildExpansionTile(context: context, viewModel: viewModel),
// _buildContainerShaderState()
],
);
Widget _buildExpansionTile(
{required BuildContext context,
required LearnSubmoduleViewModel viewModel}) =>
ExpansionTile(
enabled: true,
title: _buildTitle(),
textColor: kcDarkGrey,
showTrailingIcon: true,
initiallyExpanded: true,
subtitle: _buildContent(),
leading: _buildIconWrapper(),
collapsedIconColor: kcDarkGrey,
collapsedTextColor: kcDarkGrey,
backgroundColor: kcBackgroundColor,
shape: Border.all(color: kcTransparent),
expandedAlignment: Alignment.centerLeft,
collapsedBackgroundColor: kcBackgroundColor,
controlAffinity: ListTileControlAffinity.trailing,
expandedCrossAxisAlignment: CrossAxisAlignment.start,
tilePadding: const EdgeInsets.symmetric(horizontal: 15),
childrenPadding: const EdgeInsets.fromLTRB(70, 15, 15, 15),
// enabled: status != ProgressStatuses.pending,
// showTrailingIcon: status != ProgressStatuses.pending ? true : false,
//initiallyExpanded: status == ProgressStatuses.started ? true : false,
children:
_buildExpansionTileChildren(context: context, viewModel: viewModel),
);
Widget _buildIconWrapper() => CircleAvatar(
backgroundColor: kcPrimaryColor.withOpacity(0.1),
child: _buildIcon(),
);
Widget _buildIcon() => const Icon(
Icons.lightbulb_outline,
color: kcPrimaryColor,
);
Widget _buildTitle() => Text(
submodule.title ?? '',
maxLines: 1,
softWrap: false,
style: style16P600,
overflow: TextOverflow.ellipsis,
);
Widget _buildContent() => Text(
submodule.description ?? '',
maxLines: 1,
softWrap: false,
style: style14DG400,
overflow: TextOverflow.ellipsis,
);
List<Widget> _buildExpansionTileChildren(
{required BuildContext context,
required LearnSubmoduleViewModel viewModel}) =>
[_buildExpansionTileItem(context: context, viewModel: viewModel)];
Widget _buildExpansionTileItem(
{required BuildContext context,
required LearnSubmoduleViewModel viewModel}) =>
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: _buildExpansionTileItemChildren(
context: context, viewModel: viewModel),
);
List<Widget> _buildExpansionTileItemChildren(
{required BuildContext context,
required LearnSubmoduleViewModel viewModel}) =>
[
// _buildProgressRow(),
// verticalSpaceSmall,
_buildActionButtonWrapper(context: context, viewModel: viewModel)
];
Widget _buildProgressRow() => Row(
mainAxisSize: MainAxisSize.min,
children: _buildProgressChildren(),
);
List<Widget> _buildProgressChildren() =>
[_buildProgressStatusWrapper(), horizontalSpaceSmall, _buildProgress()];
Widget _buildProgressStatusWrapper() => Expanded(
child: _buildProgressStatus(),
);
Widget _buildProgressStatus() => const CustomLinearProgressIndicator(
progress: 0.75,
activeColor: kcPrimaryColor,
backgroundColor: kcVeryLightGrey);
Widget _buildProgress() => const Text(
'2/3',
style: TextStyle(color: kcDarkGrey),
);
Widget _buildActionButtonWrapper(
{required BuildContext context,
required LearnSubmoduleViewModel viewModel}) =>
SizedBox(
height: 40,
child: _buildActionButtons(context: context, viewModel: viewModel),
);
Widget _buildActionButtons(
{required BuildContext context,
required LearnSubmoduleViewModel viewModel}) =>
Row(
children: [
_buildLessonButtonWrapper(viewModel),
horizontalSpaceSmall,
_buildPracticeButtonWrapper(context: context, viewModel: viewModel)
],
);
Widget _buildLessonButtonWrapper(LearnSubmoduleViewModel viewModel) =>
Expanded(
child: _buildLessonButton(viewModel),
);
Widget _buildLessonButton(LearnSubmoduleViewModel viewModel) =>
CustomElevatedButton(
height: 15,
borderRadius: 12,
onTap: onLessonTap,
text: 'View Module',
foregroundColor: kcWhite,
backgroundColor: kcPrimaryColor,
// onTap: () async => await viewModel.navigateToLearnLesson(
// title: title,
// topics: topics,
// subtitle: subtitle,
// practices: practices,
// description: description),
);
Widget _buildPracticeButtonWrapper(
{required BuildContext context,
required LearnSubmoduleViewModel viewModel}) =>
Expanded(
child: _buildPracticeButton(context: context, viewModel: viewModel),
);
Widget _buildPracticeButton(
{required BuildContext context,
required LearnSubmoduleViewModel viewModel}) =>
CustomElevatedButton(
height: 15,
borderRadius: 12,
onTap: onPracticeTap,
text: 'View Practices',
backgroundColor: kcWhite,
borderColor: kcPrimaryColor,
foregroundColor: kcPrimaryColor,
// onTap: () async => await viewModel.navigateToLearnPractice(practices),
);
Widget _buildSheet(LearnSubmoduleViewModel viewModel) => FinishPracticeSheet(
onTap: viewModel.pop,
);
// Widget _buildContainerShaderState() => status == ProgressStatuses.pending
// ? _buildContainerShaderWrapper()
// : Container();
Widget _buildContainerShaderWrapper() => Positioned.fill(
child: _buildContainerShader(),
);
Widget _buildContainerShader() => Container(
decoration: BoxDecoration(
color: kcWhite.withOpacity(0.5),
borderRadius: BorderRadius.circular(5),
),
);
}

View File

@ -36,17 +36,17 @@ class ModuleProgress extends StatelessWidget {
[_buildProgressInfo(), _buildProgress()]; [_buildProgressInfo(), _buildProgress()];
Widget _buildProgressInfo() => Text( Widget _buildProgressInfo() => Text(
'0% Progress', '60% Progress',
style: style16DG400, style: style16DG400,
); );
Widget _buildProgress() => Text( Widget _buildProgress() => Text(
'0/3', '2/3',
style: style14P400, style: style14P400,
); );
Widget _buildProgressIndicator() => const CustomLinearProgressIndicator( Widget _buildProgressIndicator() => const CustomLinearProgressIndicator(
progress: 0, progress: 0.75,
activeColor: kcPrimaryColor, activeColor: kcPrimaryColor,
backgroundColor: kcVeryLightGrey, backgroundColor: kcVeryLightGrey,
); );

View File

@ -4,8 +4,7 @@ import 'package:yimaru_app/ui/common/ui_helpers.dart';
import 'package:yimaru_app/ui/widgets/custom_linear_progress_indicator.dart'; import 'package:yimaru_app/ui/widgets/custom_linear_progress_indicator.dart';
class OverallLearnProgress extends StatelessWidget { class OverallLearnProgress extends StatelessWidget {
final Color color; const OverallLearnProgress({super.key});
const OverallLearnProgress({super.key, required this.color});
@override @override
Widget build(BuildContext context) => _buildContainer(); Widget build(BuildContext context) => _buildContainer();
@ -13,8 +12,8 @@ class OverallLearnProgress extends StatelessWidget {
Widget _buildContainer() => Container( Widget _buildContainer() => Container(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 25), padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 25),
decoration: BoxDecoration( decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
color: kcPrimaryColor.withOpacity(0.1),
), ),
child: _buildProgressSection(), child: _buildProgressSection(),
); );

View File

@ -8,7 +8,6 @@
#include <audioplayers_linux/audioplayers_linux_plugin.h> #include <audioplayers_linux/audioplayers_linux_plugin.h>
#include <file_selector_linux/file_selector_plugin.h> #include <file_selector_linux/file_selector_plugin.h>
#include <flutter_inappwebview_linux/flutter_inappwebview_linux_plugin.h>
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h> #include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
#include <record_linux/record_linux_plugin.h> #include <record_linux/record_linux_plugin.h>
@ -19,9 +18,6 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
file_selector_plugin_register_with_registrar(file_selector_linux_registrar); file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
g_autoptr(FlPluginRegistrar) flutter_inappwebview_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterInappwebviewLinuxPlugin");
flutter_inappwebview_linux_plugin_register_with_registrar(flutter_inappwebview_linux_registrar);
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);

View File

@ -5,7 +5,6 @@
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
audioplayers_linux audioplayers_linux
file_selector_linux file_selector_linux
flutter_inappwebview_linux
flutter_secure_storage_linux flutter_secure_storage_linux
record_linux record_linux
) )

View File

@ -11,7 +11,6 @@ import connectivity_plus
import file_selector_macos import file_selector_macos
import firebase_core import firebase_core
import firebase_messaging import firebase_messaging
import flutter_inappwebview_macos
import flutter_local_notifications import flutter_local_notifications
import flutter_secure_storage_darwin import flutter_secure_storage_darwin
import google_sign_in_ios import google_sign_in_ios
@ -28,7 +27,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin")) FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin"))
FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin")) FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin"))

View File

@ -558,78 +558,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.0" version: "3.0.0"
flutter_inappwebview:
dependency: "direct main"
description:
name: flutter_inappwebview
sha256: "3952d116ee93bad2946401377e7ade87b5ef200e95ecb5ba1affa1b6329a6867"
url: "https://pub.dev"
source: hosted
version: "6.2.0-beta.3"
flutter_inappwebview_android:
dependency: transitive
description:
name: flutter_inappwebview_android
sha256: "8dfb76bd4e507112c3942c2272eeb01fab2e42be11374e5eb226f58698e7a04b"
url: "https://pub.dev"
source: hosted
version: "1.2.0-beta.3"
flutter_inappwebview_internal_annotations:
dependency: transitive
description:
name: flutter_inappwebview_internal_annotations
sha256: e30fba942e3debea7b7e6cdd4f0f59ce89dd403a9865193e3221293b6d1544c6
url: "https://pub.dev"
source: hosted
version: "1.3.0"
flutter_inappwebview_ios:
dependency: transitive
description:
name: flutter_inappwebview_ios
sha256: ae8a78829398771be863aa3c8804a9d40728e1815e66c9c966f86d2cc3ae4fd9
url: "https://pub.dev"
source: hosted
version: "1.2.0-beta.3"
flutter_inappwebview_linux:
dependency: transitive
description:
name: flutter_inappwebview_linux
sha256: "2e1a3b09bb911fb5a8bb155cb7f1eb1428a19b6e20363b9db48beef428b8cef5"
url: "https://pub.dev"
source: hosted
version: "0.1.0-beta.1"
flutter_inappwebview_macos:
dependency: transitive
description:
name: flutter_inappwebview_macos
sha256: "545148cb5c46475ce669ab21621e9f2ad66e05f8e80b2cf49d4018879ab52393"
url: "https://pub.dev"
source: hosted
version: "1.2.0-beta.3"
flutter_inappwebview_platform_interface:
dependency: transitive
description:
name: flutter_inappwebview_platform_interface
sha256: e3522c76e6760d1c0a9ff690e30e1503f226783d3277fa4d26675911977e9766
url: "https://pub.dev"
source: hosted
version: "1.4.0-beta.3"
flutter_inappwebview_web:
dependency: transitive
description:
name: flutter_inappwebview_web
sha256: e98b8875ccb6a3fd255873318db45c18ab135ed0ed22d20169abad9f5c810eb9
url: "https://pub.dev"
source: hosted
version: "1.2.0-beta.3"
flutter_inappwebview_windows:
dependency: transitive
description:
name: flutter_inappwebview_windows
sha256: "902edd6f6326952af822e21aa928f7426d723d45c94c15e6ce3c2d5640d28ad7"
url: "https://pub.dev"
source: hosted
version: "0.7.0-beta.3"
flutter_lints: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -1813,14 +1741,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.0" version: "2.4.0"
vimeo_video_player:
dependency: "direct main"
description:
name: vimeo_video_player
sha256: b5dc8ad763489c94136e6080ba3ee89830742a48f5e7b2e28968f54d8c3734ad
url: "https://pub.dev"
source: hosted
version: "1.0.3"
vm_service: vm_service:
dependency: transitive dependency: transitive
description: description:

View File

@ -1,7 +1,7 @@
name: yimaru_app name: yimaru_app
description: A new Flutter project. description: A new Flutter project.
publish_to: 'none' publish_to: 'none'
version: 0.1.3+5 version: 0.1.3+4
environment: environment:
sdk: '>=3.0.3 <4.0.0' sdk: '>=3.0.3 <4.0.0'
@ -38,7 +38,6 @@ dependencies:
omni_datetime_picker: any omni_datetime_picker: any
json_serializable: ^6.8.0 json_serializable: ^6.8.0
waveform_recorder: ^1.8.0 waveform_recorder: ^1.8.0
vimeo_video_player: ^1.0.3
permission_handler: ^12.0.1 permission_handler: ^12.0.1
firebase_messaging: ^16.1.1 firebase_messaging: ^16.1.1
cached_network_image: ^3.4.1 cached_network_image: ^3.4.1
@ -47,7 +46,6 @@ dependencies:
flutter_secure_storage: ^10.0.0 flutter_secure_storage: ^10.0.0
flutter_timer_countdown: ^1.0.7 flutter_timer_countdown: ^1.0.7
flutter_carousel_widget: ^3.1.0 flutter_carousel_widget: ^3.1.0
flutter_inappwebview: ^6.2.0-beta.3
flutter_local_notifications: ^20.1.0 flutter_local_notifications: ^20.1.0
internet_connection_checker_plus: ^2.9.1+2 internet_connection_checker_plus: ^2.9.1+2

View File

@ -8,42 +8,40 @@ import 'dart:ui' as _i10;
import 'package:audioplayers/audioplayers.dart' as _i4; import 'package:audioplayers/audioplayers.dart' as _i4;
import 'package:dio/dio.dart' as _i2; import 'package:dio/dio.dart' as _i2;
import 'package:firebase_messaging/firebase_messaging.dart' as _i34; import 'package:firebase_messaging/firebase_messaging.dart' as _i32;
import 'package:flutter/material.dart' as _i8; import 'package:flutter/material.dart' as _i8;
import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/mockito.dart' as _i1;
import 'package:mockito/src/dummies.dart' as _i7; import 'package:mockito/src/dummies.dart' as _i7;
import 'package:permission_handler/permission_handler.dart' as _i29; import 'package:permission_handler/permission_handler.dart' as _i27;
import 'package:stacked_services/stacked_services.dart' as _i6; import 'package:stacked_services/stacked_services.dart' as _i6;
import 'package:waveform_recorder/waveform_recorder.dart' as _i5; import 'package:waveform_recorder/waveform_recorder.dart' as _i5;
import 'package:yimaru_app/models/category.dart' as _i15; import 'package:yimaru_app/models/category.dart' as _i15;
import 'package:yimaru_app/models/course.dart' as _i21; import 'package:yimaru_app/models/course.dart' as _i21;
import 'package:yimaru_app/models/course_detail.dart' as _i37; import 'package:yimaru_app/models/course_detail.dart' as _i35;
import 'package:yimaru_app/models/course_lesson.dart' as _i18; import 'package:yimaru_app/models/course_lesson.dart' as _i18;
import 'package:yimaru_app/models/course_progress.dart' as _i17; import 'package:yimaru_app/models/course_progress.dart' as _i17;
import 'package:yimaru_app/models/lesson.dart' as _i25;
import 'package:yimaru_app/models/level.dart' as _i22; import 'package:yimaru_app/models/level.dart' as _i22;
import 'package:yimaru_app/models/module.dart' as _i23; import 'package:yimaru_app/models/module.dart' as _i23;
import 'package:yimaru_app/models/practice.dart' as _i19; import 'package:yimaru_app/models/practice.dart' as _i19;
import 'package:yimaru_app/models/practice_question.dart' as _i20; import 'package:yimaru_app/models/practice_question.dart' as _i20;
import 'package:yimaru_app/models/question.dart' as _i14; import 'package:yimaru_app/models/question.dart' as _i14;
import 'package:yimaru_app/models/subcategory.dart' as _i16; import 'package:yimaru_app/models/subcategory.dart' as _i16;
import 'package:yimaru_app/models/submodule.dart' as _i24;
import 'package:yimaru_app/models/user.dart' as _i12; import 'package:yimaru_app/models/user.dart' as _i12;
import 'package:yimaru_app/services/api_service.dart' as _i13; import 'package:yimaru_app/services/api_service.dart' as _i13;
import 'package:yimaru_app/services/audio_player_service.dart' as _i38; import 'package:yimaru_app/services/audio_player_service.dart' as _i36;
import 'package:yimaru_app/services/authentication_service.dart' as _i11; import 'package:yimaru_app/services/authentication_service.dart' as _i11;
import 'package:yimaru_app/services/course_service.dart' as _i36; import 'package:yimaru_app/services/course_service.dart' as _i34;
import 'package:yimaru_app/services/dio_service.dart' as _i26; import 'package:yimaru_app/services/dio_service.dart' as _i24;
import 'package:yimaru_app/services/google_auth_service.dart' as _i31; import 'package:yimaru_app/services/google_auth_service.dart' as _i29;
import 'package:yimaru_app/services/image_downloader_service.dart' as _i32; import 'package:yimaru_app/services/image_downloader_service.dart' as _i30;
import 'package:yimaru_app/services/image_picker_service.dart' as _i30; import 'package:yimaru_app/services/image_picker_service.dart' as _i28;
import 'package:yimaru_app/services/notification_service.dart' as _i33; import 'package:yimaru_app/services/notification_service.dart' as _i31;
import 'package:yimaru_app/services/permission_handler_service.dart' as _i28; import 'package:yimaru_app/services/permission_handler_service.dart' as _i26;
import 'package:yimaru_app/services/secure_storage_service.dart' as _i3; import 'package:yimaru_app/services/secure_storage_service.dart' as _i3;
import 'package:yimaru_app/services/smart_auth_service.dart' as _i35; import 'package:yimaru_app/services/smart_auth_service.dart' as _i33;
import 'package:yimaru_app/services/status_checker_service.dart' as _i27; import 'package:yimaru_app/services/status_checker_service.dart' as _i25;
import 'package:yimaru_app/services/voice_recorder_service.dart' as _i39; import 'package:yimaru_app/services/voice_recorder_service.dart' as _i37;
import 'package:yimaru_app/ui/common/enmus.dart' as _i40; import 'package:yimaru_app/ui/common/enmus.dart' as _i38;
// ignore_for_file: type=lint // ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_redundant_argument_values
@ -1130,7 +1128,7 @@ class MockApiService extends _i1.Mock implements _i13.ApiService {
@override @override
_i9.Future<List<_i15.Category>> getCategories() => (super.noSuchMethod( _i9.Future<List<_i15.Category>> getCategories() => (super.noSuchMethod(
Invocation.method( Invocation.method(
#getCategories, #getCourseCategories,
[], [],
), ),
returnValue: _i9.Future<List<_i15.Category>>.value(<_i15.Category>[]), returnValue: _i9.Future<List<_i15.Category>>.value(<_i15.Category>[]),
@ -1142,7 +1140,7 @@ class MockApiService extends _i1.Mock implements _i13.ApiService {
_i9.Future<List<_i16.Subcategory>> getSubcategories(int? id) => _i9.Future<List<_i16.Subcategory>> getSubcategories(int? id) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
#getSubcategories, #getCourseSubcategories,
[id], [id],
), ),
returnValue: returnValue:
@ -1272,29 +1270,6 @@ class MockApiService extends _i1.Mock implements _i13.ApiService {
returnValueForMissingStub: returnValueForMissingStub:
_i9.Future<List<_i23.Module>>.value(<_i23.Module>[]), _i9.Future<List<_i23.Module>>.value(<_i23.Module>[]),
) as _i9.Future<List<_i23.Module>>); ) as _i9.Future<List<_i23.Module>>);
@override
_i9.Future<List<_i24.Submodule>> getSubmodules(int? id) =>
(super.noSuchMethod(
Invocation.method(
#getSubmodules,
[id],
),
returnValue: _i9.Future<List<_i24.Submodule>>.value(<_i24.Submodule>[]),
returnValueForMissingStub:
_i9.Future<List<_i24.Submodule>>.value(<_i24.Submodule>[]),
) as _i9.Future<List<_i24.Submodule>>);
@override
_i9.Future<List<_i25.Lesson>> getLessons(int? id) => (super.noSuchMethod(
Invocation.method(
#getLessons,
[id],
),
returnValue: _i9.Future<List<_i25.Lesson>>.value(<_i25.Lesson>[]),
returnValueForMissingStub:
_i9.Future<List<_i25.Lesson>>.value(<_i25.Lesson>[]),
) as _i9.Future<List<_i25.Lesson>>);
} }
/// A class which mocks [SecureStorageService]. /// A class which mocks [SecureStorageService].
@ -1397,7 +1372,7 @@ class MockSecureStorageService extends _i1.Mock
/// A class which mocks [DioService]. /// A class which mocks [DioService].
/// ///
/// See the documentation for Mockito's code generation for more information. /// See the documentation for Mockito's code generation for more information.
class MockDioService extends _i1.Mock implements _i26.DioService { class MockDioService extends _i1.Mock implements _i24.DioService {
@override @override
_i2.Dio get dio => (super.noSuchMethod( _i2.Dio get dio => (super.noSuchMethod(
Invocation.getter(#dio), Invocation.getter(#dio),
@ -1416,7 +1391,7 @@ class MockDioService extends _i1.Mock implements _i26.DioService {
/// ///
/// See the documentation for Mockito's code generation for more information. /// See the documentation for Mockito's code generation for more information.
class MockStatusCheckerService extends _i1.Mock class MockStatusCheckerService extends _i1.Mock
implements _i27.StatusCheckerService { implements _i25.StatusCheckerService {
@override @override
_i3.SecureStorageService get storage => (super.noSuchMethod( _i3.SecureStorageService get storage => (super.noSuchMethod(
Invocation.getter(#storage), Invocation.getter(#storage),
@ -1482,40 +1457,40 @@ class MockStatusCheckerService extends _i1.Mock
/// ///
/// See the documentation for Mockito's code generation for more information. /// See the documentation for Mockito's code generation for more information.
class MockPermissionHandlerService extends _i1.Mock class MockPermissionHandlerService extends _i1.Mock
implements _i28.PermissionHandlerService { implements _i26.PermissionHandlerService {
@override @override
_i9.Future<_i29.PermissionStatus> requestPermission( _i9.Future<_i27.PermissionStatus> requestPermission(
_i29.Permission? requestedPermission) => _i27.Permission? requestedPermission) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
#requestPermission, #requestPermission,
[requestedPermission], [requestedPermission],
), ),
returnValue: _i9.Future<_i29.PermissionStatus>.value( returnValue: _i9.Future<_i27.PermissionStatus>.value(
_i29.PermissionStatus.denied), _i27.PermissionStatus.denied),
returnValueForMissingStub: _i9.Future<_i29.PermissionStatus>.value( returnValueForMissingStub: _i9.Future<_i27.PermissionStatus>.value(
_i29.PermissionStatus.denied), _i27.PermissionStatus.denied),
) as _i9.Future<_i29.PermissionStatus>); ) as _i9.Future<_i27.PermissionStatus>);
@override @override
_i9.Future<_i29.PermissionStatus> request(_i29.Permission? permission) => _i9.Future<_i27.PermissionStatus> request(_i27.Permission? permission) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
#request, #request,
[permission], [permission],
), ),
returnValue: _i9.Future<_i29.PermissionStatus>.value( returnValue: _i9.Future<_i27.PermissionStatus>.value(
_i29.PermissionStatus.denied), _i27.PermissionStatus.denied),
returnValueForMissingStub: _i9.Future<_i29.PermissionStatus>.value( returnValueForMissingStub: _i9.Future<_i27.PermissionStatus>.value(
_i29.PermissionStatus.denied), _i27.PermissionStatus.denied),
) as _i9.Future<_i29.PermissionStatus>); ) as _i9.Future<_i27.PermissionStatus>);
} }
/// A class which mocks [ImagePickerService]. /// A class which mocks [ImagePickerService].
/// ///
/// See the documentation for Mockito's code generation for more information. /// See the documentation for Mockito's code generation for more information.
class MockImagePickerService extends _i1.Mock class MockImagePickerService extends _i1.Mock
implements _i30.ImagePickerService { implements _i28.ImagePickerService {
@override @override
_i9.Future<String?> gallery() => (super.noSuchMethod( _i9.Future<String?> gallery() => (super.noSuchMethod(
Invocation.method( Invocation.method(
@ -1540,7 +1515,7 @@ class MockImagePickerService extends _i1.Mock
/// A class which mocks [GoogleAuthService]. /// A class which mocks [GoogleAuthService].
/// ///
/// See the documentation for Mockito's code generation for more information. /// See the documentation for Mockito's code generation for more information.
class MockGoogleAuthService extends _i1.Mock implements _i31.GoogleAuthService { class MockGoogleAuthService extends _i1.Mock implements _i29.GoogleAuthService {
@override @override
int get listenersCount => (super.noSuchMethod( int get listenersCount => (super.noSuchMethod(
Invocation.getter(#listenersCount), Invocation.getter(#listenersCount),
@ -1610,7 +1585,7 @@ class MockGoogleAuthService extends _i1.Mock implements _i31.GoogleAuthService {
/// ///
/// See the documentation for Mockito's code generation for more information. /// See the documentation for Mockito's code generation for more information.
class MockImageDownloaderService extends _i1.Mock class MockImageDownloaderService extends _i1.Mock
implements _i32.ImageDownloaderService { implements _i30.ImageDownloaderService {
@override @override
_i9.Future<String> downloader(String? networkImage) => (super.noSuchMethod( _i9.Future<String> downloader(String? networkImage) => (super.noSuchMethod(
Invocation.method( Invocation.method(
@ -1639,7 +1614,7 @@ class MockImageDownloaderService extends _i1.Mock
/// ///
/// See the documentation for Mockito's code generation for more information. /// See the documentation for Mockito's code generation for more information.
class MockNotificationService extends _i1.Mock class MockNotificationService extends _i1.Mock
implements _i33.NotificationService { implements _i31.NotificationService {
@override @override
_i9.Future<void> initialize() => (super.noSuchMethod( _i9.Future<void> initialize() => (super.noSuchMethod(
Invocation.method( Invocation.method(
@ -1661,7 +1636,7 @@ class MockNotificationService extends _i1.Mock
) as _i9.Future<void>); ) as _i9.Future<void>);
@override @override
_i9.Future<void> showNotification(_i34.RemoteMessage? message) => _i9.Future<void> showNotification(_i32.RemoteMessage? message) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
#showNotification, #showNotification,
@ -1695,7 +1670,7 @@ class MockNotificationService extends _i1.Mock
/// A class which mocks [SmartAuthService]. /// A class which mocks [SmartAuthService].
/// ///
/// See the documentation for Mockito's code generation for more information. /// See the documentation for Mockito's code generation for more information.
class MockSmartAuthService extends _i1.Mock implements _i35.SmartAuthService { class MockSmartAuthService extends _i1.Mock implements _i33.SmartAuthService {
@override @override
bool get listenForMultipleSms => (super.noSuchMethod( bool get listenForMultipleSms => (super.noSuchMethod(
Invocation.getter(#listenForMultipleSms), Invocation.getter(#listenForMultipleSms),
@ -1727,26 +1702,26 @@ class MockSmartAuthService extends _i1.Mock implements _i35.SmartAuthService {
/// A class which mocks [CourseService]. /// A class which mocks [CourseService].
/// ///
/// See the documentation for Mockito's code generation for more information. /// See the documentation for Mockito's code generation for more information.
class MockCourseService extends _i1.Mock implements _i36.CourseService { class MockCourseService extends _i1.Mock implements _i34.CourseService {
@override @override
_i9.Future<List<_i37.CourseDetail>> getCoursesDetail(int? id) => _i9.Future<List<_i35.CourseDetail>> getCoursesDetail(int? id) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
#getCoursesDetail, #getCoursesDetail,
[id], [id],
), ),
returnValue: returnValue:
_i9.Future<List<_i37.CourseDetail>>.value(<_i37.CourseDetail>[]), _i9.Future<List<_i35.CourseDetail>>.value(<_i35.CourseDetail>[]),
returnValueForMissingStub: returnValueForMissingStub:
_i9.Future<List<_i37.CourseDetail>>.value(<_i37.CourseDetail>[]), _i9.Future<List<_i35.CourseDetail>>.value(<_i35.CourseDetail>[]),
) as _i9.Future<List<_i37.CourseDetail>>); ) as _i9.Future<List<_i35.CourseDetail>>);
} }
/// A class which mocks [AudioPlayerService]. /// A class which mocks [AudioPlayerService].
/// ///
/// See the documentation for Mockito's code generation for more information. /// See the documentation for Mockito's code generation for more information.
class MockAudioPlayerService extends _i1.Mock class MockAudioPlayerService extends _i1.Mock
implements _i38.AudioPlayerService { implements _i36.AudioPlayerService {
@override @override
_i4.AudioPlayer get player => (super.noSuchMethod( _i4.AudioPlayer get player => (super.noSuchMethod(
Invocation.getter(#player), Invocation.getter(#player),
@ -1870,13 +1845,13 @@ class MockAudioPlayerService extends _i1.Mock
/// ///
/// See the documentation for Mockito's code generation for more information. /// See the documentation for Mockito's code generation for more information.
class MockVoiceRecorderService extends _i1.Mock class MockVoiceRecorderService extends _i1.Mock
implements _i39.VoiceRecorderService { implements _i37.VoiceRecorderService {
@override @override
_i40.VoiceRecordingState get recordingState => (super.noSuchMethod( _i38.VoiceRecordingState get recordingState => (super.noSuchMethod(
Invocation.getter(#recordingState), Invocation.getter(#recordingState),
returnValue: _i40.VoiceRecordingState.pending, returnValue: _i38.VoiceRecordingState.pending,
returnValueForMissingStub: _i40.VoiceRecordingState.pending, returnValueForMissingStub: _i38.VoiceRecordingState.pending,
) as _i40.VoiceRecordingState); ) as _i38.VoiceRecordingState);
@override @override
_i5.WaveformRecorderController get waveController => (super.noSuchMethod( _i5.WaveformRecorderController get waveController => (super.noSuchMethod(

View File

@ -1,11 +0,0 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:yimaru_app/app/app.locator.dart';
import '../helpers/test_helpers.dart';
void main() {
group('LearnSubmoduleViewModel Tests -', () {
setUp(() => registerServices());
tearDown(() => locator.reset());
});
}

View File

@ -11,7 +11,6 @@
#include <connectivity_plus/connectivity_plus_windows_plugin.h> #include <connectivity_plus/connectivity_plus_windows_plugin.h>
#include <file_selector_windows/file_selector_windows.h> #include <file_selector_windows/file_selector_windows.h>
#include <firebase_core/firebase_core_plugin_c_api.h> #include <firebase_core/firebase_core_plugin_c_api.h>
#include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h>
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h> #include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h> #include <permission_handler_windows/permission_handler_windows_plugin.h>
#include <record_windows/record_windows_plugin_c_api.h> #include <record_windows/record_windows_plugin_c_api.h>
@ -27,8 +26,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("FileSelectorWindows")); registry->GetRegistrarForPlugin("FileSelectorWindows"));
FirebaseCorePluginCApiRegisterWithRegistrar( FirebaseCorePluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); registry->GetRegistrarForPlugin("FirebaseCorePluginCApi"));
FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi"));
FlutterSecureStorageWindowsPluginRegisterWithRegistrar( FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
PermissionHandlerWindowsPluginRegisterWithRegistrar( PermissionHandlerWindowsPluginRegisterWithRegistrar(

View File

@ -8,7 +8,6 @@ list(APPEND FLUTTER_PLUGIN_LIST
connectivity_plus connectivity_plus
file_selector_windows file_selector_windows
firebase_core firebase_core
flutter_inappwebview_windows
flutter_secure_storage_windows flutter_secure_storage_windows
permission_handler_windows permission_handler_windows
record_windows record_windows