Merge branch 'main' into 5208-exiting-practice

This commit is contained in:
Ava Shilling 2026-01-16 13:24:25 -05:00
commit faa6143a6a
8 changed files with 69 additions and 41 deletions

View file

@ -50,7 +50,13 @@ class AnalyticsDownloadDialogState extends State<AnalyticsDownloadDialog> {
}
void _setDownloadType(DownloadType type) {
if (mounted) setState(() => _downloadType = type);
if (mounted) {
setState(() {
_downloadType = type;
_downloaded = false;
_error = null;
});
}
}
Future<void> _downloadAnalytics() async {
@ -427,7 +433,8 @@ class AnalyticsDownloadDialogState extends State<AnalyticsDownloadDialog> {
padding: const EdgeInsets.all(8.0),
child: SegmentedButton<DownloadType>(
selected: {_downloadType},
onSelectionChanged: (c) => _setDownloadType(c.first),
onSelectionChanged:
_downloading ? null : (c) => _setDownloadType(c.first),
segments: [
ButtonSegment(
value: DownloadType.csv,

View file

@ -154,6 +154,7 @@ class BotChatSettingsDialogState extends State<BotChatSettingsDialog> {
initialLevel: _selectedLevel,
onChanged: _setLevel,
enabled: !widget.room.isActivitySession,
width: 300,
),
DropdownButtonFormField2<String>(
customButton: _selectedVoice != null

View file

@ -296,7 +296,7 @@ class SpaceDetailsContent extends StatelessWidget {
],
Flexible(
child: Column(
spacing: 12.0,
spacing: isColumnMode ? 12.0 : 6.0,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -311,7 +311,7 @@ class SpaceDetailsContent extends StatelessWidget {
: FontWeight.bold,
),
),
if (isColumnMode && room.coursePlan != null)
if (room.coursePlan != null)
CourseInfoChips(
room.coursePlan!.uuid,
fontSize: 12.0,

View file

@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/common/widgets/dropdown_text_button.dart';
import 'package:fluffychat/pangea/learning_settings/language_level_type_enum.dart';
@ -14,6 +13,7 @@ class LanguageLevelDropdown extends StatelessWidget {
final FormFieldValidator<Object>? validator;
final bool enabled;
final Color? backgroundColor;
final double? width;
const LanguageLevelDropdown({
super.key,
@ -22,6 +22,7 @@ class LanguageLevelDropdown extends StatelessWidget {
this.validator,
this.enabled = true,
this.backgroundColor,
this.width,
});
@override
@ -33,12 +34,12 @@ class LanguageLevelDropdown extends StatelessWidget {
LanguageLevelTypeEnum.values.contains(initialLevel)
? CustomDropdownTextButton(text: initialLevel!.title(context))
: null,
menuItemStyleData: MenuItemStyleData(
padding: const EdgeInsets.symmetric(
menuItemStyleData: const MenuItemStyleData(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 16.0,
),
height: FluffyThemes.isColumnMode(context) ? 100.0 : 150.0,
height: 100.0,
),
decoration: InputDecoration(
labelText: l10n.cefrLevelLabel,
@ -51,6 +52,7 @@ class LanguageLevelDropdown extends StatelessWidget {
Theme.of(context).colorScheme.surfaceContainerHigh,
borderRadius: BorderRadius.circular(14.0),
),
width: width,
),
items:
LanguageLevelTypeEnum.values.map((LanguageLevelTypeEnum levelOption) {

View file

@ -122,7 +122,9 @@ class PangeaController {
}
Future<void> _clearCache({List<String> exclude = const []}) async {
final List<Future<void>> futures = [];
final List<Future<void>> futures = [
matrixState.store.setString(SettingKeys.fontSizeFactor, ''),
];
for (final key in _storageKeys) {
if (exclude.contains(key)) continue;
futures.add(GetStorage(key).erase());
@ -140,6 +142,7 @@ class PangeaController {
);
}
AppConfig.fontSizeFactor = 1.0;
await Future.wait(futures);
}

View file

@ -169,12 +169,12 @@ class SelectedCourseController extends State<SelectedCourse>
: await client.joinRoom(widget.roomChunk!.roomId);
Room? room = client.getRoomById(roomId);
if (!knock && room == null) {
await client.waitForRoomInSync(roomId);
if (!knock && room?.membership != Membership.join) {
await client.waitForRoomInSync(roomId, join: true);
room = client.getRoomById(roomId);
}
if (knock && room == null) {
if (knock) {
Navigator.of(context).pop();
await showOkAlertDialog(
context: context,

View file

@ -10,6 +10,7 @@ import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/analytics_misc/client_analytics_extension.dart';
import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
import 'package:fluffychat/pangea/space_analytics/space_analytics_requested_dialog.dart';
import 'package:fluffychat/utils/stream_extension.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
class AnalyticsRequestIndicator extends StatefulWidget {
@ -26,51 +27,68 @@ class AnalyticsRequestIndicator extends StatefulWidget {
class AnalyticsRequestIndicatorState extends State<AnalyticsRequestIndicator> {
AnalyticsRequestIndicatorState();
final Map<User, List<Room>> _knockingAdmins = {};
StreamSubscription? _analyticsRoomSub;
@override
void initState() {
super.initState();
_fetchKnockingAdmins();
_init();
}
@override
void didUpdateWidget(covariant AnalyticsRequestIndicator oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.room.id != widget.room.id) {
_fetchKnockingAdmins();
_init();
}
}
Future<void> _fetchKnockingAdmins() async {
setState(() => _knockingAdmins.clear());
@override
void dispose() {
_analyticsRoomSub?.cancel();
super.dispose();
}
final admins = (await widget.room.requestParticipants(
[Membership.join, Membership.invite, Membership.knock],
false,
true,
))
.where((u) => u.powerLevel >= 100);
Future<void> _init() async {
final analyticsRooms = widget.room.client.allMyAnalyticsRooms;
final futures = analyticsRooms.map(
(r) => r.requestParticipants(
[Membership.join, Membership.invite, Membership.knock],
false,
true,
),
);
await Future.wait(futures);
final analyicsRoomIds = analyticsRooms.map((r) => r.id).toSet();
_analyticsRoomSub?.cancel();
_analyticsRoomSub = widget.room.client.onRoomState.stream
.where(
(event) =>
analyicsRoomIds.contains(event.roomId) &&
event.state.type == EventTypes.RoomMember,
)
.rateLimit(const Duration(seconds: 1))
.listen((_) => setState(() {}));
if (mounted) setState(() {});
}
Map<User, List<Room>> get _knockingAdmins {
final Map<User, List<Room>> knockingAdmins = {};
for (final analyticsRoom in widget.room.client.allMyAnalyticsRooms) {
final knocking = await analyticsRoom.requestParticipants(
[Membership.knock],
);
final knockingSpace =
knocking.where((u) => u.content['reason'] == widget.room.id).toList();
if (knockingSpace.isEmpty) continue;
final knocking = analyticsRoom
.getParticipants([Membership.knock])
.where((u) => u.content['reason'] == widget.room.id)
.toList();
for (final admin in admins) {
if (knockingSpace.any((u) => u.id == admin.id)) {
_knockingAdmins.putIfAbsent(admin, () => []).add(analyticsRoom);
}
if (knocking.isEmpty) continue;
for (final admin in knocking) {
knockingAdmins.putIfAbsent(admin, () => []).add(analyticsRoom);
}
}
if (mounted) {
setState(() {});
}
return knockingAdmins;
}
Future<void> _onTap(BuildContext context) async {
@ -109,8 +127,6 @@ class AnalyticsRequestIndicatorState extends State<AnalyticsRequestIndicator> {
}
},
);
if (mounted) _fetchKnockingAdmins();
}
@override

View file

@ -100,7 +100,6 @@ class _GameChoiceCardState extends State<GameChoiceCard>
animation: _scaleAnim,
builder: (context, _) {
final scale = _scaleAnim.value;
final showAlt = scale < 0.1 && widget.altChild != null;
final showContent = scale > 0.05;
return Transform.scale(
@ -113,7 +112,7 @@ class _GameChoiceCardState extends State<GameChoiceCard>
: (hovered ? hoverColor : Colors.transparent),
child: Opacity(
opacity: showContent ? 1 : 0,
child: showAlt ? widget.altChild! : widget.child,
child: _revealed ? widget.altChild! : widget.child,
),
),
);