parent
141d3c5175
commit
7d46892a39
@ -1,29 +1,108 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/pangea/analytics_page/activity_archive_view.dart';
|
import 'package:fluffychat/config/app_config.dart';
|
||||||
|
import 'package:fluffychat/pangea/activity_sessions/activity_room_extension.dart';
|
||||||
|
import 'package:fluffychat/widgets/hover_builder.dart';
|
||||||
|
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
|
||||||
import 'package:fluffychat/widgets/matrix.dart';
|
import 'package:fluffychat/widgets/matrix.dart';
|
||||||
|
import '../../config/themes.dart';
|
||||||
|
import '../../widgets/avatar.dart';
|
||||||
|
|
||||||
class ActivityArchive extends StatefulWidget {
|
class ActivityArchive extends StatelessWidget {
|
||||||
const ActivityArchive({super.key});
|
const ActivityArchive({super.key});
|
||||||
|
|
||||||
@override
|
|
||||||
ActivityArchiveState createState() => ActivityArchiveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class ActivityArchiveState extends State<ActivityArchive> {
|
|
||||||
List<Room> get archive =>
|
List<Room> get archive =>
|
||||||
MatrixState.pangeaController.getAnalytics.archivedActivities;
|
MatrixState.pangeaController.getAnalytics.archivedActivities;
|
||||||
|
|
||||||
Future<void> removeArchivedChat(Room room) async {
|
@override
|
||||||
await room.leave();
|
Widget build(BuildContext context) {
|
||||||
await MatrixState.pangeaController.putAnalytics
|
return MaxWidthBody(
|
||||||
.removeActivityAnalytics(room.id);
|
withScrolling: false,
|
||||||
|
child: Builder(
|
||||||
setState(() {});
|
builder: (BuildContext context) {
|
||||||
|
if (archive.isEmpty) {
|
||||||
|
return const Center(
|
||||||
|
child: Icon(Icons.archive_outlined, size: 80),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: archive.length,
|
||||||
|
itemBuilder: (BuildContext context, int i) => AnalyticsActivityItem(
|
||||||
|
room: archive[i],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AnalyticsActivityItem extends StatelessWidget {
|
||||||
|
final Room room;
|
||||||
|
const AnalyticsActivityItem({
|
||||||
|
super.key,
|
||||||
|
required this.room,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => ActivityArchiveView(controller: this);
|
Widget build(BuildContext context) {
|
||||||
|
final objective = room.activityPlan?.learningObjective ?? '';
|
||||||
|
final cefrLevel = room.activitySummary?.summary?.participants
|
||||||
|
.firstWhereOrNull(
|
||||||
|
(p) => p.participantId == room.client.userID,
|
||||||
|
)
|
||||||
|
?.cefrLevel;
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 8,
|
||||||
|
vertical: 1,
|
||||||
|
),
|
||||||
|
child: Material(
|
||||||
|
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
child: ListTile(
|
||||||
|
visualDensity: const VisualDensity(vertical: -0.5),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
leading: HoverBuilder(
|
||||||
|
builder: (context, hovered) => AnimatedScale(
|
||||||
|
duration: FluffyThemes.animationDuration,
|
||||||
|
curve: FluffyThemes.animationCurve,
|
||||||
|
scale: hovered ? 1.1 : 1.0,
|
||||||
|
child: Avatar(
|
||||||
|
borderRadius: BorderRadius.circular(4.0),
|
||||||
|
mxContent: room.avatar,
|
||||||
|
name: room.getLocalizedDisplayname(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
objective,
|
||||||
|
maxLines: 3,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: const TextStyle(fontSize: 12.0),
|
||||||
|
),
|
||||||
|
trailing: cefrLevel != null
|
||||||
|
? Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 8,
|
||||||
|
vertical: 4,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
cefrLevel.toUpperCase(),
|
||||||
|
style: const TextStyle(fontSize: 14.0),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
onTap: () => context.go(
|
||||||
|
'/rooms/analytics/activities/${room.id}',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,48 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:go_router/go_router.dart';
|
|
||||||
|
|
||||||
import 'package:fluffychat/pages/chat_list/chat_list_item.dart';
|
|
||||||
import 'package:fluffychat/pangea/analytics_page/activity_archive.dart';
|
|
||||||
import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
|
||||||
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
|
|
||||||
|
|
||||||
class ActivityArchiveView extends StatelessWidget {
|
|
||||||
final ActivityArchiveState controller;
|
|
||||||
const ActivityArchiveView({
|
|
||||||
super.key,
|
|
||||||
required this.controller,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MaxWidthBody(
|
|
||||||
withScrolling: false,
|
|
||||||
child: Builder(
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
if (controller.archive.isEmpty) {
|
|
||||||
return const Center(
|
|
||||||
child: Icon(Icons.archive_outlined, size: 80),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return ListView.builder(
|
|
||||||
itemCount: controller.archive.length,
|
|
||||||
itemBuilder: (BuildContext context, int i) => ChatListItem(
|
|
||||||
controller.archive[i],
|
|
||||||
onForget: () {
|
|
||||||
showFutureLoadingDialog(
|
|
||||||
context: context,
|
|
||||||
future: () => controller.removeArchivedChat(
|
|
||||||
controller.archive[i],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onTap: () =>
|
|
||||||
context.go('/rooms/analytics/${controller.archive[i].id}'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,46 +1,89 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/pangea/analytics_page/analytics_page_view.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
|
||||||
|
import 'package:fluffychat/config/app_config.dart';
|
||||||
|
import 'package:fluffychat/config/themes.dart';
|
||||||
|
import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup.dart';
|
||||||
|
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||||
|
import 'package:fluffychat/pangea/analytics_page/activity_archive.dart';
|
||||||
|
import 'package:fluffychat/pangea/analytics_page/analytics_page_constants.dart';
|
||||||
|
import 'package:fluffychat/pangea/analytics_summary/learning_progress_indicators.dart';
|
||||||
|
import 'package:fluffychat/pangea/analytics_summary/level_dialog_content.dart';
|
||||||
import 'package:fluffychat/pangea/analytics_summary/progress_indicators_enum.dart';
|
import 'package:fluffychat/pangea/analytics_summary/progress_indicators_enum.dart';
|
||||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||||
import 'package:fluffychat/widgets/matrix.dart';
|
import 'package:fluffychat/widgets/matrix.dart';
|
||||||
|
|
||||||
class AnalyticsPage extends StatefulWidget {
|
class AnalyticsPage extends StatelessWidget {
|
||||||
final ProgressIndicatorEnum? selectedIndicator;
|
final ProgressIndicatorEnum? indicator;
|
||||||
final ConstructIdentifier? constructZoom;
|
final ConstructIdentifier? construct;
|
||||||
|
final bool isSidebar;
|
||||||
|
|
||||||
const AnalyticsPage({
|
const AnalyticsPage({
|
||||||
super.key,
|
super.key,
|
||||||
this.selectedIndicator,
|
this.indicator,
|
||||||
this.constructZoom,
|
this.construct,
|
||||||
|
this.isSidebar = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
AnalyticsPageState createState() => AnalyticsPageState();
|
Widget build(BuildContext context) {
|
||||||
}
|
return Scaffold(
|
||||||
|
appBar: construct != null ? AppBar() : null,
|
||||||
class AnalyticsPageState extends State<AnalyticsPage> {
|
body: SafeArea(
|
||||||
ProgressIndicatorEnum? selectedIndicator = ProgressIndicatorEnum.wordsUsed;
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsGeometry.all(16.0),
|
||||||
@override
|
child: Column(
|
||||||
void initState() {
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
super.initState();
|
children: [
|
||||||
// init the analytics controllers
|
if (isSidebar ||
|
||||||
MatrixState.pangeaController.initControllers();
|
(!FluffyThemes.isColumnMode(context) && construct == null))
|
||||||
selectedIndicator = widget.selectedIndicator ??
|
LearningProgressIndicators(
|
||||||
ProgressIndicatorEnum.wordsUsed; // Default to wordsUsed if not set
|
selected: indicator,
|
||||||
}
|
canSelect: indicator != ProgressIndicatorEnum.level,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: StreamBuilder(
|
||||||
|
stream: MatrixState
|
||||||
|
.pangeaController.getAnalytics.analyticsStream.stream,
|
||||||
|
builder: (context, _) {
|
||||||
|
if (indicator == ProgressIndicatorEnum.level) {
|
||||||
|
return const LevelDialogContent();
|
||||||
|
} else if (indicator == ProgressIndicatorEnum.morphsUsed) {
|
||||||
|
return ConstructAnalyticsView(
|
||||||
|
construct: construct,
|
||||||
|
view: ConstructTypeEnum.morph,
|
||||||
|
);
|
||||||
|
} else if (indicator == ProgressIndicatorEnum.wordsUsed) {
|
||||||
|
return ConstructAnalyticsView(
|
||||||
|
construct: construct,
|
||||||
|
view: ConstructTypeEnum.vocab,
|
||||||
|
);
|
||||||
|
} else if (indicator == ProgressIndicatorEnum.activities) {
|
||||||
|
return const ActivityArchive();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
return Center(
|
||||||
void didUpdateWidget(covariant AnalyticsPage oldWidget) {
|
child: SizedBox(
|
||||||
super.didUpdateWidget(oldWidget);
|
width: 250.0,
|
||||||
if (oldWidget.selectedIndicator != widget.selectedIndicator &&
|
child: CachedNetworkImage(
|
||||||
widget.selectedIndicator != null) {
|
imageUrl:
|
||||||
setState(
|
"${AppConfig.assetsBaseURL}/${AnalyticsPageConstants.dinoBotFileName}",
|
||||||
() => selectedIndicator = widget.selectedIndicator!,
|
errorWidget: (context, url, error) =>
|
||||||
); // Update to new value
|
const SizedBox(),
|
||||||
}
|
placeholder: (context, url) => const Center(
|
||||||
|
child: CircularProgressIndicator.adaptive(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) => AnalyticsPageView(controller: this);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,68 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup.dart';
|
|
||||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
|
||||||
import 'package:fluffychat/pangea/analytics_page/activity_archive.dart';
|
|
||||||
import 'package:fluffychat/pangea/analytics_page/analytics_page.dart';
|
|
||||||
import 'package:fluffychat/pangea/analytics_summary/learning_progress_indicators.dart';
|
|
||||||
import 'package:fluffychat/pangea/analytics_summary/level_dialog_content.dart';
|
|
||||||
import 'package:fluffychat/pangea/analytics_summary/progress_indicators_enum.dart';
|
|
||||||
import 'package:fluffychat/widgets/matrix.dart';
|
|
||||||
|
|
||||||
class AnalyticsPageView extends StatelessWidget {
|
|
||||||
final AnalyticsPageState controller;
|
|
||||||
const AnalyticsPageView({
|
|
||||||
super.key,
|
|
||||||
required this.controller,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body: SafeArea(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsetsGeometry.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
LearningProgressIndicators(
|
|
||||||
selected: controller.selectedIndicator,
|
|
||||||
canSelect:
|
|
||||||
controller.selectedIndicator != ProgressIndicatorEnum.level,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: StreamBuilder(
|
|
||||||
stream: MatrixState
|
|
||||||
.pangeaController.getAnalytics.analyticsStream.stream,
|
|
||||||
builder: (context, _) {
|
|
||||||
if (controller.selectedIndicator ==
|
|
||||||
ProgressIndicatorEnum.level) {
|
|
||||||
return const LevelDialogContent();
|
|
||||||
} else if (controller.selectedIndicator ==
|
|
||||||
ProgressIndicatorEnum.morphsUsed) {
|
|
||||||
return AnalyticsPopupWrapper(
|
|
||||||
constructZoom: controller.widget.constructZoom,
|
|
||||||
view: ConstructTypeEnum.morph,
|
|
||||||
);
|
|
||||||
} else if (controller.selectedIndicator ==
|
|
||||||
ProgressIndicatorEnum.wordsUsed) {
|
|
||||||
return AnalyticsPopupWrapper(
|
|
||||||
constructZoom: controller.widget.constructZoom,
|
|
||||||
view: ConstructTypeEnum.vocab,
|
|
||||||
);
|
|
||||||
} else if (controller.selectedIndicator ==
|
|
||||||
ProgressIndicatorEnum.activities) {
|
|
||||||
return const ActivityArchive();
|
|
||||||
}
|
|
||||||
|
|
||||||
return const SizedBox();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue