fix(learn): Integrate learn lessons according to the new hierarchy
This commit is contained in:
parent
2050bd332c
commit
9323f73bb4
File diff suppressed because one or more lines are too long
|
|
@ -52,6 +52,7 @@ 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(
|
||||||
|
|
@ -92,6 +93,7 @@ import 'package:yimaru_app/ui/views/learn_subcategory/learn_subcategory_view.dar
|
||||||
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
52
lib/models/lesson.dart
Normal file
52
lib/models/lesson.dart
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
35
lib/models/lesson.g.dart
Normal file
35
lib/models/lesson.g.dart
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
// 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,
|
||||||
|
};
|
||||||
44
lib/models/submodule.dart
Normal file
44
lib/models/submodule.dart
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
31
lib/models/submodule.g.dart
Normal file
31
lib/models/submodule.g.dart
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
// 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,
|
||||||
|
};
|
||||||
|
|
@ -13,7 +13,9 @@ 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 {
|
||||||
|
|
@ -674,4 +676,52 @@ 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 [];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ String kCoursesUrl = 'courses';
|
||||||
|
|
||||||
String kModulesUrl = 'modules';
|
String kModulesUrl = 'modules';
|
||||||
|
|
||||||
|
String kLessonsUrl = 'lessons';
|
||||||
|
|
||||||
String kRegisterUrl = 'register';
|
String kRegisterUrl = 'register';
|
||||||
|
|
||||||
String kCategoryUrl = 'categories';
|
String kCategoryUrl = 'categories';
|
||||||
|
|
@ -24,6 +26,8 @@ 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';
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ enum StateObjects {
|
||||||
verifyOtp,
|
verifyOtp,
|
||||||
resendOtp,
|
resendOtp,
|
||||||
learnLevels,
|
learnLevels,
|
||||||
|
learnLessons,
|
||||||
learnModules,
|
learnModules,
|
||||||
learnCourses,
|
learnCourses,
|
||||||
profileImage,
|
profileImage,
|
||||||
|
|
@ -40,6 +41,7 @@ enum StateObjects {
|
||||||
loginWithGoogle,
|
loginWithGoogle,
|
||||||
loadLessonVideo,
|
loadLessonVideo,
|
||||||
loadCourseVideo,
|
loadCourseVideo,
|
||||||
|
learnSubmodules,
|
||||||
requestResetCode,
|
requestResetCode,
|
||||||
courseCategories,
|
courseCategories,
|
||||||
profileCompletion,
|
profileCompletion,
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,8 @@ class CourseCategoryViewModel extends ReactiveViewModel {
|
||||||
// Remote api call
|
// Remote api call
|
||||||
|
|
||||||
// Course categories
|
// Course categories
|
||||||
Future<void> getCategories() async =>
|
Future<void> getCategories() async => await runBusyFuture(_getCategories(),
|
||||||
await runBusyFuture(_getCategories(),
|
busyObject: StateObjects.courseCategories);
|
||||||
busyObject: StateObjects.courseCategories);
|
|
||||||
|
|
||||||
Future<void> _getCategories() async {
|
Future<void> _getCategories() async {
|
||||||
if (categories.isEmpty) {
|
if (categories.isEmpty) {
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ 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));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,30 @@
|
||||||
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_elevated_button.dart';
|
import '../../widgets/custom_circular_progress_indicator.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 String title;
|
final Submodule submodule;
|
||||||
final String topics;
|
|
||||||
final String subtitle;
|
const LearnLessonView({Key? key, required this.submodule}) : super(key: key);
|
||||||
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;
|
||||||
|
|
@ -117,95 +116,63 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
|
||||||
verticalSpaceTiny,
|
verticalSpaceTiny,
|
||||||
_buildSubtitle(),
|
_buildSubtitle(),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildTopics(),
|
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
// _buildModuleProgress(),
|
_buildModuleProgress(),
|
||||||
// verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
// _buildContinueButton(),
|
verticalSpaceMedium,
|
||||||
// verticalSpaceMedium,
|
_buildMotivationCard(),
|
||||||
// _buildMotivationCard(),
|
verticalSpaceMedium,
|
||||||
// verticalSpaceMedium,
|
_buildHeader(),
|
||||||
//_buildHeader(),
|
verticalSpaceMedium,
|
||||||
//verticalSpaceMedium,
|
_buildListViewBuilder(viewModel),
|
||||||
// _buildListView(viewModel),
|
|
||||||
getPadding(context),
|
|
||||||
_buildStartButton(viewModel),
|
|
||||||
verticalSpaceSmall,
|
|
||||||
_buildPracticeButton(viewModel)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
title,
|
submodule.title ?? '',
|
||||||
style: style16DG600,
|
style: style16DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
subtitle,
|
submodule.description ?? '',
|
||||||
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(
|
||||||
title,
|
'Lessons in this module',
|
||||||
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(
|
||||||
title: viewModel.lessons[index]['title'],
|
lesson: viewModel.lessons[index],
|
||||||
status: viewModel.lessons[index]['status'],
|
onLessonTap: () async => await viewModel.navigateToLearnLessonDetail(viewModel.lessons[index]),
|
||||||
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 String title,
|
required Lesson lesson,
|
||||||
required String thumbnail,
|
required GestureTapCallback? onLessonTap,
|
||||||
GestureTapCallback? onLessonTap,
|
|
||||||
required ProgressStatuses status,
|
|
||||||
GestureTapCallback? onPracticeTap,
|
|
||||||
}) =>
|
}) =>
|
||||||
LearnLessonTile(
|
LearnLessonTile(
|
||||||
title: title,
|
lesson: lesson,
|
||||||
status: status,
|
|
||||||
thumbnail: thumbnail,
|
|
||||||
onLessonTap: onLessonTap,
|
onLessonTap: onLessonTap,
|
||||||
onPracticeTap: onPracticeTap,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,47 +4,42 @@ 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>();
|
||||||
|
|
||||||
// Lessons
|
// Learn lessons
|
||||||
final List<Map<String, dynamic>> _lessons = [
|
List<Lesson> _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<Map<String, dynamic>> get lessons => _lessons;
|
List<Lesson> get lessons => _lessons;
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
|
|
||||||
Future<void> navigateToLearnLessonDetail(
|
Future<void> navigateToLearnLessonDetail(Lesson lesson) async =>
|
||||||
{required String title,
|
await _navigationService.navigateToLearnLessonDetailView(lesson: lesson);
|
||||||
required List<Map<String, dynamic>> practices,
|
|
||||||
required String description}) async =>
|
|
||||||
await _navigationService.navigateToLearnLessonDetailView(
|
|
||||||
title: title, practices: practices, description: description);
|
|
||||||
|
|
||||||
Future<void> navigateToLearnPractice(
|
// Remote api call
|
||||||
List<Map<String, dynamic>> practices) async =>
|
|
||||||
await _navigationService.navigateToLearnPracticeView(
|
// Learn modules
|
||||||
practices: practices,
|
Future<void> getLessons(int id) async => await runBusyFuture(_getLessons(id),
|
||||||
title: 'Let’s Practice',
|
busyObject: StateObjects.learnLessons);
|
||||||
buttonLabel: 'Begin Lesson Practice',
|
|
||||||
subtitle: 'Let’s quickly review what you’ve learned in this lesson!',
|
Future<void> _getLessons(int id) async {
|
||||||
);
|
if (_lessons.isEmpty) {
|
||||||
|
if (await _statusChecker.checkConnection()) {
|
||||||
|
_lessons = await _apiService.getLessons(id);
|
||||||
|
_lessons.sort(
|
||||||
|
(a, b) => (a.displayOrder ?? 0).compareTo(b.displayOrder ?? 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
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';
|
||||||
|
|
@ -11,20 +12,14 @@ 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 String title;
|
final Lesson lesson;
|
||||||
final String description;
|
|
||||||
final List<Map<String, dynamic>> practices;
|
|
||||||
|
|
||||||
const LearnLessonDetailView(
|
const LearnLessonDetailView({Key? key, required this.lesson})
|
||||||
{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
|
||||||
|
|
@ -34,12 +29,6 @@ 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();
|
||||||
|
|
@ -125,7 +114,7 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
title,
|
lesson.title ?? '',
|
||||||
style: style16DG600,
|
style: style16DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -134,21 +123,21 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
|
||||||
height: 200,
|
height: 200,
|
||||||
color: kcBlack,
|
color: kcBlack,
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
child: _buildVideoPlayerState(viewModel),
|
child: _buildVideoPlayer(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) =>
|
||||||
_buildChewiePlayer(viewModel);
|
_buildVimeoPlayer(viewModel);
|
||||||
|
|
||||||
Widget _buildChewiePlayer(LearnLessonDetailViewModel viewModel) =>
|
Widget _buildVimeoPlayer(LearnLessonDetailViewModel viewModel) =>
|
||||||
Chewie(controller: viewModel.chewieController!);
|
VimeoVideoPlayer(
|
||||||
|
isAutoPlay: true,
|
||||||
|
onInAppWebViewCreated: (controller) =>
|
||||||
|
viewModel.initializePlayer(controller),
|
||||||
|
videoId: lesson.teachingVideoUrl?.split('/').last ?? '',
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildEmptyVideoPlayer() => const EmptyVideoPlayer();
|
Widget _buildEmptyVideoPlayer() => const EmptyVideoPlayer();
|
||||||
|
|
||||||
|
|
@ -158,7 +147,7 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildDescription() => Text(
|
Widget _buildDescription() => Text(
|
||||||
description,
|
lesson.description ?? '',
|
||||||
style: style14DG600,
|
style: style14DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -175,7 +164,7 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
|
||||||
Widget _buildContinueButton(LearnLessonDetailViewModel viewModel) =>
|
Widget _buildContinueButton(LearnLessonDetailViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Practice',
|
text: 'Lessons',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
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';
|
||||||
|
|
@ -20,6 +19,10 @@ 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;
|
||||||
|
|
@ -34,32 +37,22 @@ class LearnLessonDetailViewModel extends BaseViewModel {
|
||||||
await _chewieController?.pause();
|
await _chewieController?.pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> initializePlayer() async =>
|
void initializePlayer(InAppWebViewController controller){
|
||||||
await runBusyFuture(_initializePlayer(),
|
_webViewController = controller;
|
||||||
busyObject: StateObjects.loadLessonVideo);
|
rebuildUi();
|
||||||
|
|
||||||
Future<void> _initializePlayer() async {
|
|
||||||
_videoPlayerController =
|
|
||||||
VideoPlayerController.networkUrl(Uri.parse(kSampleVideoUrl));
|
|
||||||
|
|
||||||
await _videoPlayerController?.initialize();
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onLoadVideoStart() {
|
||||||
|
setBusyForObject(StateObjects.loadLessonVideo, true);
|
||||||
|
rebuildUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onLoadVideoComplete() {
|
||||||
|
setBusyForObject(StateObjects.loadLessonVideo, false);
|
||||||
|
rebuildUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ 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,
|
||||||
);
|
);
|
||||||
|
|
@ -82,7 +83,8 @@ 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 => await viewModel.navigateToModule( viewModel.levels[index]),
|
onTap: () async =>
|
||||||
|
await viewModel.navigateToModule(viewModel.levels[index]),
|
||||||
),
|
),
|
||||||
separatorBuilder: (context, index) => verticalSpaceSmall,
|
separatorBuilder: (context, index) => verticalSpaceSmall,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
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';
|
||||||
|
|
||||||
|
|
@ -57,6 +58,7 @@ 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,
|
||||||
);
|
);
|
||||||
|
|
@ -79,10 +81,10 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
_buildSubtitle(),
|
_buildSubtitle(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceLarge,
|
||||||
_buildOverallProgress(),
|
_buildOverallProgress(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildListView(viewModel)
|
_buildListViewBuilder(viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
|
|
@ -95,26 +97,36 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
|
||||||
style: style14DG400,
|
style: style14DG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildOverallProgress() => const OverallLearnProgress();
|
Widget _buildOverallProgress() => 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],
|
||||||
onLessonTap: () {},
|
onModuleTap: () async => await viewModel
|
||||||
onPracticeTap: () {}),
|
.navigateToLearnSubmodule(viewModel.modules[index]),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTile({
|
Widget _buildTile({
|
||||||
required Module module,
|
required Module module,
|
||||||
required GestureTapCallback onLessonTap,
|
required GestureTapCallback onModuleTap,
|
||||||
required GestureTapCallback onPracticeTap,
|
|
||||||
}) =>
|
}) =>
|
||||||
LearnModuleTile(
|
LearnModuleTile(
|
||||||
module: module,
|
module: module,
|
||||||
onLessonTap: onLessonTap,
|
onModuleTap: onModuleTap,
|
||||||
onPracticeTap: onPracticeTap,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,27 +24,8 @@ class LearnModuleViewModel extends BaseViewModel {
|
||||||
// Navigation
|
// Navigation
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
|
|
||||||
Future<void> navigateToLearnLesson(
|
Future<void> navigateToLearnSubmodule(Module module) async =>
|
||||||
{required String title,
|
await _navigationService.navigateToLearnSubmoduleView(module: module);
|
||||||
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: 'Let’s Practice',
|
|
||||||
buttonLabel: 'Begin Lesson Practice',
|
|
||||||
subtitle: 'Let’s quickly review what you’ve learned in this lesson!',
|
|
||||||
);
|
|
||||||
|
|
||||||
// Remote api call
|
// Remote api call
|
||||||
|
|
||||||
|
|
|
||||||
146
lib/ui/views/learn_submodule/learn_submodule_view.dart
Normal file
146
lib/ui/views/learn_submodule/learn_submodule_view.dart
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
46
lib/ui/views/learn_submodule/learn_submodule_viewmodel.dart
Normal file
46
lib/ui/views/learn_submodule/learn_submodule_viewmodel.dart
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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: 150,
|
height: 125,
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
padding: const EdgeInsets.all(15),
|
padding: const EdgeInsets.all(15),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,17 @@
|
||||||
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 String title;
|
final Lesson lesson;
|
||||||
final String thumbnail;
|
|
||||||
final ProgressStatuses status;
|
|
||||||
final GestureTapCallback? onLessonTap;
|
final GestureTapCallback? onLessonTap;
|
||||||
final GestureTapCallback? onPracticeTap;
|
|
||||||
|
|
||||||
const LearnLessonTile({
|
const LearnLessonTile({super.key, this.onLessonTap, required this.lesson});
|
||||||
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();
|
||||||
|
|
@ -32,50 +22,55 @@ class LearnLessonTile extends StatelessWidget {
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(5),
|
borderRadius: BorderRadius.circular(5),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: ProgressStatuses.pending == status
|
color: kcPrimaryColor.withOpacity(0.1),
|
||||||
? kcPrimaryColor.withOpacity(0.1)
|
// color: ProgressStatuses.pending == status
|
||||||
: kcGreen.withOpacity(0.1),
|
// ? kcPrimaryColor.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,
|
||||||
trailing: _buildIconState(),
|
initiallyExpanded: true,
|
||||||
// subtitle: _buildContent(),
|
trailing: _buildPendingIcon(),
|
||||||
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,
|
||||||
enabled: status != ProgressStatuses.pending,
|
backgroundColor: kcGreen.withOpacity(0.1),
|
||||||
controlAffinity: ListTileControlAffinity.trailing,
|
controlAffinity: ListTileControlAffinity.trailing,
|
||||||
backgroundColor: ProgressStatuses.pending == status
|
|
||||||
? kcPrimaryColor.withOpacity(0.1)
|
|
||||||
: kcGreen.withOpacity(0.1),
|
|
||||||
childrenPadding: const EdgeInsets.fromLTRB(15, 15, 15, 15),
|
|
||||||
expandedCrossAxisAlignment: CrossAxisAlignment.start,
|
expandedCrossAxisAlignment: CrossAxisAlignment.start,
|
||||||
collapsedBackgroundColor: ProgressStatuses.pending == status
|
collapsedBackgroundColor: kcPrimaryColor.withOpacity(0.1),
|
||||||
? kcPrimaryColor.withOpacity(0.1)
|
childrenPadding: const EdgeInsets.fromLTRB(15, 15, 15, 15),
|
||||||
: kcGreen.withOpacity(0.1),
|
|
||||||
tilePadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
|
tilePadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
|
||||||
initiallyExpanded: status != ProgressStatuses.completed ? true : false,
|
// enabled: status != ProgressStatuses.pending,
|
||||||
|
// 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() => MiniThumbnail(thumbnail: thumbnail);
|
Widget _buildLeadingWrapper() =>
|
||||||
|
MiniThumbnail(thumbnail: lesson.thumbnail ?? 'assets/images/image_1.png');
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
title,
|
lesson.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,
|
||||||
|
|
@ -98,58 +93,35 @@ class LearnLessonTile extends StatelessWidget {
|
||||||
List<Widget> _buildExpansionTileItemChildren() => [
|
List<Widget> _buildExpansionTileItemChildren() => [
|
||||||
_buildProgress(),
|
_buildProgress(),
|
||||||
horizontalSpaceSmall,
|
horizontalSpaceSmall,
|
||||||
_buildProgressText(),
|
// _buildProgressText(),
|
||||||
verticalSpaceSmall,
|
// verticalSpaceSmall,
|
||||||
_buildActionButtonWrapper()
|
_buildActionButtonWrapper()
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildProgress() => CustomLinearProgressIndicator(
|
Widget _buildProgress() => const 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: 40,
|
height: 50,
|
||||||
child: _buildActionButtons(),
|
child: _buildLessonButton(),
|
||||||
);
|
|
||||||
|
|
||||||
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,
|
||||||
width: 135,
|
text: 'Start',
|
||||||
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',
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,14 @@ 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? onLessonTap;
|
final GestureTapCallback? onModuleTap;
|
||||||
final GestureTapCallback? onPracticeTap;
|
|
||||||
|
|
||||||
const LearnModuleTile(
|
const LearnModuleTile({super.key, this.onModuleTap, required this.module});
|
||||||
{super.key, this.onLessonTap, this.onPracticeTap, required this.module});
|
|
||||||
|
|
||||||
Future<void> _showSheet(
|
Future<void> _showSheet(
|
||||||
{required BuildContext context,
|
{required BuildContext context,
|
||||||
|
|
@ -158,7 +155,7 @@ class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
|
||||||
required LearnModuleViewModel viewModel}) =>
|
required LearnModuleViewModel viewModel}) =>
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: _buildActionButtons(context: context, viewModel: viewModel),
|
child: _buildModuleButton(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildActionButtons(
|
Widget _buildActionButtons(
|
||||||
|
|
@ -166,46 +163,39 @@ class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
|
||||||
required LearnModuleViewModel viewModel}) =>
|
required LearnModuleViewModel viewModel}) =>
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
_buildLessonButtonWrapper(viewModel),
|
_buildModuleButtonWrapper(viewModel),
|
||||||
horizontalSpaceSmall,
|
horizontalSpaceSmall,
|
||||||
_buildPracticeButtonWrapper(context: context, viewModel: viewModel)
|
_buildPracticeButtonWrapper(context: context, viewModel: viewModel)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLessonButtonWrapper(LearnModuleViewModel viewModel) => Expanded(
|
Widget _buildModuleButtonWrapper(LearnModuleViewModel viewModel) => Expanded(
|
||||||
child: _buildLessonButton(viewModel),
|
child: _buildModuleButton(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLessonButton(LearnModuleViewModel viewModel) =>
|
Widget _buildModuleButton(LearnModuleViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 15,
|
height: 15,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
onTap: onLessonTap,
|
onTap: onModuleTap,
|
||||||
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: _buildPracticeButton(context: context, viewModel: viewModel),
|
child: Container(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildPracticeButton(
|
Widget _buildPracticeButton(
|
||||||
{required BuildContext context,
|
{required BuildContext context,
|
||||||
required LearnModuleViewModel viewModel}) =>
|
required LearnModuleViewModel viewModel}) =>
|
||||||
CustomElevatedButton(
|
const 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,
|
||||||
|
|
|
||||||
237
lib/ui/widgets/learn_submodule_tile.dart
Normal file
237
lib/ui/widgets/learn_submodule_tile.dart
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
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),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -36,17 +36,17 @@ class ModuleProgress extends StatelessWidget {
|
||||||
[_buildProgressInfo(), _buildProgress()];
|
[_buildProgressInfo(), _buildProgress()];
|
||||||
|
|
||||||
Widget _buildProgressInfo() => Text(
|
Widget _buildProgressInfo() => Text(
|
||||||
'60% Progress',
|
'0% Progress',
|
||||||
style: style16DG400,
|
style: style16DG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildProgress() => Text(
|
Widget _buildProgress() => Text(
|
||||||
'2/3',
|
'0/3',
|
||||||
style: style14P400,
|
style: style14P400,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildProgressIndicator() => const CustomLinearProgressIndicator(
|
Widget _buildProgressIndicator() => const CustomLinearProgressIndicator(
|
||||||
progress: 0.75,
|
progress: 0,
|
||||||
activeColor: kcPrimaryColor,
|
activeColor: kcPrimaryColor,
|
||||||
backgroundColor: kcVeryLightGrey,
|
backgroundColor: kcVeryLightGrey,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ 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 {
|
||||||
const OverallLearnProgress({super.key});
|
final Color color;
|
||||||
|
const OverallLearnProgress({super.key, required this.color});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => _buildContainer();
|
Widget build(BuildContext context) => _buildContainer();
|
||||||
|
|
@ -12,8 +13,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(),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#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>
|
||||||
|
|
||||||
|
|
@ -18,6 +19,9 @@ 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);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
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
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ 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
|
||||||
|
|
@ -27,6 +28,7 @@ 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"))
|
||||||
|
|
|
||||||
80
pubspec.lock
80
pubspec.lock
|
|
@ -558,6 +558,78 @@ 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:
|
||||||
|
|
@ -1741,6 +1813,14 @@ 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:
|
||||||
|
|
|
||||||
|
|
@ -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+4
|
version: 0.1.3+5
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.0.3 <4.0.0'
|
sdk: '>=3.0.3 <4.0.0'
|
||||||
|
|
@ -38,6 +38,7 @@ 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
|
||||||
|
|
@ -46,6 +47,7 @@ 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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,40 +8,42 @@ 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 _i32;
|
import 'package:firebase_messaging/firebase_messaging.dart' as _i34;
|
||||||
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 _i27;
|
import 'package:permission_handler/permission_handler.dart' as _i29;
|
||||||
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 _i35;
|
import 'package:yimaru_app/models/course_detail.dart' as _i37;
|
||||||
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 _i36;
|
import 'package:yimaru_app/services/audio_player_service.dart' as _i38;
|
||||||
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 _i34;
|
import 'package:yimaru_app/services/course_service.dart' as _i36;
|
||||||
import 'package:yimaru_app/services/dio_service.dart' as _i24;
|
import 'package:yimaru_app/services/dio_service.dart' as _i26;
|
||||||
import 'package:yimaru_app/services/google_auth_service.dart' as _i29;
|
import 'package:yimaru_app/services/google_auth_service.dart' as _i31;
|
||||||
import 'package:yimaru_app/services/image_downloader_service.dart' as _i30;
|
import 'package:yimaru_app/services/image_downloader_service.dart' as _i32;
|
||||||
import 'package:yimaru_app/services/image_picker_service.dart' as _i28;
|
import 'package:yimaru_app/services/image_picker_service.dart' as _i30;
|
||||||
import 'package:yimaru_app/services/notification_service.dart' as _i31;
|
import 'package:yimaru_app/services/notification_service.dart' as _i33;
|
||||||
import 'package:yimaru_app/services/permission_handler_service.dart' as _i26;
|
import 'package:yimaru_app/services/permission_handler_service.dart' as _i28;
|
||||||
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 _i33;
|
import 'package:yimaru_app/services/smart_auth_service.dart' as _i35;
|
||||||
import 'package:yimaru_app/services/status_checker_service.dart' as _i25;
|
import 'package:yimaru_app/services/status_checker_service.dart' as _i27;
|
||||||
import 'package:yimaru_app/services/voice_recorder_service.dart' as _i37;
|
import 'package:yimaru_app/services/voice_recorder_service.dart' as _i39;
|
||||||
import 'package:yimaru_app/ui/common/enmus.dart' as _i38;
|
import 'package:yimaru_app/ui/common/enmus.dart' as _i40;
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: avoid_redundant_argument_values
|
// ignore_for_file: avoid_redundant_argument_values
|
||||||
|
|
@ -1128,7 +1130,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(
|
||||||
#getCourseCategories,
|
#getCategories,
|
||||||
[],
|
[],
|
||||||
),
|
),
|
||||||
returnValue: _i9.Future<List<_i15.Category>>.value(<_i15.Category>[]),
|
returnValue: _i9.Future<List<_i15.Category>>.value(<_i15.Category>[]),
|
||||||
|
|
@ -1140,7 +1142,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(
|
||||||
#getCourseSubcategories,
|
#getSubcategories,
|
||||||
[id],
|
[id],
|
||||||
),
|
),
|
||||||
returnValue:
|
returnValue:
|
||||||
|
|
@ -1270,6 +1272,29 @@ 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].
|
||||||
|
|
@ -1372,7 +1397,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 _i24.DioService {
|
class MockDioService extends _i1.Mock implements _i26.DioService {
|
||||||
@override
|
@override
|
||||||
_i2.Dio get dio => (super.noSuchMethod(
|
_i2.Dio get dio => (super.noSuchMethod(
|
||||||
Invocation.getter(#dio),
|
Invocation.getter(#dio),
|
||||||
|
|
@ -1391,7 +1416,7 @@ class MockDioService extends _i1.Mock implements _i24.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 _i25.StatusCheckerService {
|
implements _i27.StatusCheckerService {
|
||||||
@override
|
@override
|
||||||
_i3.SecureStorageService get storage => (super.noSuchMethod(
|
_i3.SecureStorageService get storage => (super.noSuchMethod(
|
||||||
Invocation.getter(#storage),
|
Invocation.getter(#storage),
|
||||||
|
|
@ -1457,40 +1482,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 _i26.PermissionHandlerService {
|
implements _i28.PermissionHandlerService {
|
||||||
@override
|
@override
|
||||||
_i9.Future<_i27.PermissionStatus> requestPermission(
|
_i9.Future<_i29.PermissionStatus> requestPermission(
|
||||||
_i27.Permission? requestedPermission) =>
|
_i29.Permission? requestedPermission) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#requestPermission,
|
#requestPermission,
|
||||||
[requestedPermission],
|
[requestedPermission],
|
||||||
),
|
),
|
||||||
returnValue: _i9.Future<_i27.PermissionStatus>.value(
|
returnValue: _i9.Future<_i29.PermissionStatus>.value(
|
||||||
_i27.PermissionStatus.denied),
|
_i29.PermissionStatus.denied),
|
||||||
returnValueForMissingStub: _i9.Future<_i27.PermissionStatus>.value(
|
returnValueForMissingStub: _i9.Future<_i29.PermissionStatus>.value(
|
||||||
_i27.PermissionStatus.denied),
|
_i29.PermissionStatus.denied),
|
||||||
) as _i9.Future<_i27.PermissionStatus>);
|
) as _i9.Future<_i29.PermissionStatus>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i9.Future<_i27.PermissionStatus> request(_i27.Permission? permission) =>
|
_i9.Future<_i29.PermissionStatus> request(_i29.Permission? permission) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#request,
|
#request,
|
||||||
[permission],
|
[permission],
|
||||||
),
|
),
|
||||||
returnValue: _i9.Future<_i27.PermissionStatus>.value(
|
returnValue: _i9.Future<_i29.PermissionStatus>.value(
|
||||||
_i27.PermissionStatus.denied),
|
_i29.PermissionStatus.denied),
|
||||||
returnValueForMissingStub: _i9.Future<_i27.PermissionStatus>.value(
|
returnValueForMissingStub: _i9.Future<_i29.PermissionStatus>.value(
|
||||||
_i27.PermissionStatus.denied),
|
_i29.PermissionStatus.denied),
|
||||||
) as _i9.Future<_i27.PermissionStatus>);
|
) as _i9.Future<_i29.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 _i28.ImagePickerService {
|
implements _i30.ImagePickerService {
|
||||||
@override
|
@override
|
||||||
_i9.Future<String?> gallery() => (super.noSuchMethod(
|
_i9.Future<String?> gallery() => (super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
|
@ -1515,7 +1540,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 _i29.GoogleAuthService {
|
class MockGoogleAuthService extends _i1.Mock implements _i31.GoogleAuthService {
|
||||||
@override
|
@override
|
||||||
int get listenersCount => (super.noSuchMethod(
|
int get listenersCount => (super.noSuchMethod(
|
||||||
Invocation.getter(#listenersCount),
|
Invocation.getter(#listenersCount),
|
||||||
|
|
@ -1585,7 +1610,7 @@ class MockGoogleAuthService extends _i1.Mock implements _i29.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 _i30.ImageDownloaderService {
|
implements _i32.ImageDownloaderService {
|
||||||
@override
|
@override
|
||||||
_i9.Future<String> downloader(String? networkImage) => (super.noSuchMethod(
|
_i9.Future<String> downloader(String? networkImage) => (super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
|
@ -1614,7 +1639,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 _i31.NotificationService {
|
implements _i33.NotificationService {
|
||||||
@override
|
@override
|
||||||
_i9.Future<void> initialize() => (super.noSuchMethod(
|
_i9.Future<void> initialize() => (super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
|
@ -1636,7 +1661,7 @@ class MockNotificationService extends _i1.Mock
|
||||||
) as _i9.Future<void>);
|
) as _i9.Future<void>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i9.Future<void> showNotification(_i32.RemoteMessage? message) =>
|
_i9.Future<void> showNotification(_i34.RemoteMessage? message) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#showNotification,
|
#showNotification,
|
||||||
|
|
@ -1670,7 +1695,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 _i33.SmartAuthService {
|
class MockSmartAuthService extends _i1.Mock implements _i35.SmartAuthService {
|
||||||
@override
|
@override
|
||||||
bool get listenForMultipleSms => (super.noSuchMethod(
|
bool get listenForMultipleSms => (super.noSuchMethod(
|
||||||
Invocation.getter(#listenForMultipleSms),
|
Invocation.getter(#listenForMultipleSms),
|
||||||
|
|
@ -1702,26 +1727,26 @@ class MockSmartAuthService extends _i1.Mock implements _i33.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 _i34.CourseService {
|
class MockCourseService extends _i1.Mock implements _i36.CourseService {
|
||||||
@override
|
@override
|
||||||
_i9.Future<List<_i35.CourseDetail>> getCoursesDetail(int? id) =>
|
_i9.Future<List<_i37.CourseDetail>> getCoursesDetail(int? id) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#getCoursesDetail,
|
#getCoursesDetail,
|
||||||
[id],
|
[id],
|
||||||
),
|
),
|
||||||
returnValue:
|
returnValue:
|
||||||
_i9.Future<List<_i35.CourseDetail>>.value(<_i35.CourseDetail>[]),
|
_i9.Future<List<_i37.CourseDetail>>.value(<_i37.CourseDetail>[]),
|
||||||
returnValueForMissingStub:
|
returnValueForMissingStub:
|
||||||
_i9.Future<List<_i35.CourseDetail>>.value(<_i35.CourseDetail>[]),
|
_i9.Future<List<_i37.CourseDetail>>.value(<_i37.CourseDetail>[]),
|
||||||
) as _i9.Future<List<_i35.CourseDetail>>);
|
) as _i9.Future<List<_i37.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 _i36.AudioPlayerService {
|
implements _i38.AudioPlayerService {
|
||||||
@override
|
@override
|
||||||
_i4.AudioPlayer get player => (super.noSuchMethod(
|
_i4.AudioPlayer get player => (super.noSuchMethod(
|
||||||
Invocation.getter(#player),
|
Invocation.getter(#player),
|
||||||
|
|
@ -1845,13 +1870,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 _i37.VoiceRecorderService {
|
implements _i39.VoiceRecorderService {
|
||||||
@override
|
@override
|
||||||
_i38.VoiceRecordingState get recordingState => (super.noSuchMethod(
|
_i40.VoiceRecordingState get recordingState => (super.noSuchMethod(
|
||||||
Invocation.getter(#recordingState),
|
Invocation.getter(#recordingState),
|
||||||
returnValue: _i38.VoiceRecordingState.pending,
|
returnValue: _i40.VoiceRecordingState.pending,
|
||||||
returnValueForMissingStub: _i38.VoiceRecordingState.pending,
|
returnValueForMissingStub: _i40.VoiceRecordingState.pending,
|
||||||
) as _i38.VoiceRecordingState);
|
) as _i40.VoiceRecordingState);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i5.WaveformRecorderController get waveController => (super.noSuchMethod(
|
_i5.WaveformRecorderController get waveController => (super.noSuchMethod(
|
||||||
|
|
|
||||||
11
test/viewmodels/learn_submodule_viewmodel_test.dart
Normal file
11
test/viewmodels/learn_submodule_viewmodel_test.dart
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
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());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#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>
|
||||||
|
|
@ -26,6 +27,8 @@ 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(
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ 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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user