Merge branch 'main' into 737-private-class-code
This commit is contained in:
commit
2900634900
14 changed files with 252 additions and 128 deletions
|
|
@ -4234,5 +4234,9 @@
|
|||
"reportContentIssueTitle": "Report content issue",
|
||||
"feedback": "Optional feedback",
|
||||
"reportContentIssueDescription": "Uh oh! AI can faciliate personalized learning experiences but... also hallucinates. Please provide any feedback you have and we'll try again.",
|
||||
"clickTheWordAgainToDeselect": "Click the selected word to deselect it."
|
||||
"clickTheWordAgainToDeselect": "Click the selected word to deselect it.",
|
||||
"l2SupportNa": "Not Available",
|
||||
"l2SupportAlpha": "Alpha",
|
||||
"l2SupportBeta": "Beta",
|
||||
"l2SupportFull": "Full"
|
||||
}
|
||||
|
|
@ -470,6 +470,14 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
// #Pangea
|
||||
// On iOS, if the toolbar is open and the app is closed, then the user goes
|
||||
// back to do more toolbar activities, the toolbar buttons / selection don't
|
||||
// update properly. So, when the user closes the app, close the toolbar overlay.
|
||||
if (state == AppLifecycleState.paused) {
|
||||
clearSelectedEvents();
|
||||
}
|
||||
// Pangea#
|
||||
if (state != AppLifecycleState.resumed) return;
|
||||
setReadMarker();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ class IgcController {
|
|||
return;
|
||||
}
|
||||
|
||||
choreographer.chatController.inputFocus.unfocus();
|
||||
OverlayUtil.showPositionedCard(
|
||||
context: context,
|
||||
cardToShow: SpanCard(
|
||||
|
|
@ -124,7 +125,7 @@ class IgcController {
|
|||
),
|
||||
roomId: choreographer.roomId,
|
||||
),
|
||||
cardSize: match.isITStart ? const Size(350, 260) : const Size(400, 400),
|
||||
cardSize: match.isITStart ? const Size(350, 260) : const Size(350, 350),
|
||||
transformTargetId: choreographer.inputTransformTargetKey,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -308,6 +308,8 @@ class ITChoices extends StatelessWidget {
|
|||
);
|
||||
return;
|
||||
}
|
||||
|
||||
controller.choreographer.chatController.inputFocus.unfocus();
|
||||
OverlayUtil.showPositionedCard(
|
||||
context: context,
|
||||
cardToShow: choiceFeedback == null
|
||||
|
|
|
|||
|
|
@ -27,7 +27,9 @@ class PangeaLanguage {
|
|||
static Future<void> initialize() async {
|
||||
try {
|
||||
_langList = await _getCachedFlags();
|
||||
if (await _shouldFetch || _langList.isEmpty) {
|
||||
if (await _shouldFetch ||
|
||||
_langList.isEmpty ||
|
||||
_langList.every((lang) => !lang.l2)) {
|
||||
_langList = await LanguageRepo.fetchLanguages();
|
||||
|
||||
await _saveFlags(_langList);
|
||||
|
|
|
|||
98
lib/pangea/enum/l2_support_enum.dart
Normal file
98
lib/pangea/enum/l2_support_enum.dart
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
enum L2SupportEnum {
|
||||
na,
|
||||
alpha,
|
||||
beta,
|
||||
full,
|
||||
}
|
||||
|
||||
extension L2SupportEnumExtension on L2SupportEnum {
|
||||
String get storageString {
|
||||
switch (this) {
|
||||
case L2SupportEnum.na:
|
||||
return 'na';
|
||||
case L2SupportEnum.alpha:
|
||||
return 'alpha';
|
||||
case L2SupportEnum.beta:
|
||||
return 'beta';
|
||||
case L2SupportEnum.full:
|
||||
return 'full';
|
||||
}
|
||||
}
|
||||
|
||||
L2SupportEnum fromStorageString(String storageString) {
|
||||
switch (storageString) {
|
||||
case 'na':
|
||||
case 'L2SupportEnum.na':
|
||||
return L2SupportEnum.na;
|
||||
case 'alpha':
|
||||
case 'L2SupportEnum.alpha':
|
||||
return L2SupportEnum.alpha;
|
||||
case 'beta':
|
||||
case 'L2SupportEnum.beta':
|
||||
return L2SupportEnum.beta;
|
||||
case 'full':
|
||||
case 'L2SupportEnum.full':
|
||||
return L2SupportEnum.full;
|
||||
default:
|
||||
throw Exception('Unknown L2SupportEnum storage string: $storageString');
|
||||
}
|
||||
}
|
||||
|
||||
String toLocalizedString(BuildContext context) {
|
||||
final l10n = L10n.of(context)!;
|
||||
|
||||
switch (this) {
|
||||
case L2SupportEnum.na:
|
||||
return l10n.l2SupportNa;
|
||||
case L2SupportEnum.alpha:
|
||||
return l10n.l2SupportAlpha;
|
||||
case L2SupportEnum.beta:
|
||||
return l10n.l2SupportBeta;
|
||||
case L2SupportEnum.full:
|
||||
return l10n.l2SupportFull;
|
||||
}
|
||||
}
|
||||
|
||||
Badge toBadge(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
Color color;
|
||||
String label;
|
||||
|
||||
switch (this) {
|
||||
case L2SupportEnum.na:
|
||||
color = theme.colorScheme.onSurface.withOpacity(0.4); // Muted grey
|
||||
label = toLocalizedString(context);
|
||||
break;
|
||||
case L2SupportEnum.alpha:
|
||||
color = theme.colorScheme.primary.withOpacity(0.4); // Subtle primary
|
||||
label = toLocalizedString(context);
|
||||
break;
|
||||
case L2SupportEnum.beta:
|
||||
color =
|
||||
theme.colorScheme.secondary.withOpacity(0.4); // Subtle secondary
|
||||
label = toLocalizedString(context);
|
||||
break;
|
||||
case L2SupportEnum.full:
|
||||
color = theme.colorScheme.tertiary.withOpacity(0.4); // Subtle tertiary
|
||||
label = toLocalizedString(context);
|
||||
break;
|
||||
}
|
||||
|
||||
return Badge(
|
||||
label: Text(
|
||||
label,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: theme.colorScheme.onSurface.withOpacity(0.8), // Dimmed text
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
backgroundColor: color,
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
smallSize: 20, // A smaller badge for subtlety
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:fluffychat/pangea/constants/language_constants.dart';
|
||||
import 'package:fluffychat/pangea/enum/l2_support_enum.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
|
@ -12,15 +13,15 @@ class LanguageModel {
|
|||
final String languageFlag;
|
||||
final String displayName;
|
||||
final String? languageEmoji;
|
||||
final bool l2;
|
||||
final bool l1;
|
||||
final L2SupportEnum l2Support;
|
||||
|
||||
LanguageModel({
|
||||
required this.langCode,
|
||||
required this.languageFlag,
|
||||
required this.displayName,
|
||||
required this.l2,
|
||||
required this.l1,
|
||||
this.l2Support = L2SupportEnum.na,
|
||||
this.languageEmoji,
|
||||
});
|
||||
|
||||
|
|
@ -37,9 +38,11 @@ class LanguageModel {
|
|||
displayName: _LanguageLocal.getDisplayName(
|
||||
code != LanguageKeys.unknownLanguage ? code : json['language_name'],
|
||||
),
|
||||
l2: json["l2"] ?? code.contains("es") || code.contains("en"),
|
||||
l1: json["l1"] ?? !code.contains("es") && !code.contains("en"),
|
||||
languageEmoji: json['language_emoji'],
|
||||
l2Support: json['l2_support'] != null
|
||||
? L2SupportEnum.na.fromStorageString(json['l2_support'])
|
||||
: L2SupportEnum.na,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -47,11 +50,13 @@ class LanguageModel {
|
|||
'language_code': langCode,
|
||||
'language_name': displayName,
|
||||
'language_flag': languageFlag,
|
||||
'l2': l2,
|
||||
'l1': l1,
|
||||
'language_emoji': languageEmoji,
|
||||
'l2_support': l2Support.storageString,
|
||||
};
|
||||
|
||||
bool get l2 => l2Support != L2SupportEnum.na;
|
||||
|
||||
// Discuss with Jordan - adding langCode field to language objects as separate from displayName
|
||||
static String codeFromNameOrCode(String codeOrName, [String? url]) {
|
||||
if (codeOrName.isEmpty) return LanguageKeys.unknownLanguage;
|
||||
|
|
@ -73,7 +78,6 @@ class LanguageModel {
|
|||
langCode: LanguageKeys.unknownLanguage,
|
||||
languageFlag: "",
|
||||
displayName: "Unknown",
|
||||
l2: false,
|
||||
l1: false,
|
||||
);
|
||||
|
||||
|
|
@ -81,16 +85,12 @@ class LanguageModel {
|
|||
displayName: context != null
|
||||
? L10n.of(context)!.multiLingualSpace
|
||||
: "Multilingual Space",
|
||||
l2: false,
|
||||
l1: false,
|
||||
langCode: LanguageKeys.multiLanguage,
|
||||
languageFlag: 'assets/colors.png',
|
||||
languageEmoji: "🌎",
|
||||
);
|
||||
|
||||
// Discuss with Jordan
|
||||
bool get hasContextualDefinitionSupport => l2;
|
||||
|
||||
String? getDisplayName(BuildContext context) {
|
||||
switch (langCode) {
|
||||
case 'ab':
|
||||
|
|
|
|||
|
|
@ -234,6 +234,7 @@ class LanguageSelectionRow extends StatelessWidget {
|
|||
targetLanguage: isSource ? null : language,
|
||||
);
|
||||
},
|
||||
isL2List: !isSource,
|
||||
initialLanguage: isSource
|
||||
? controller.sourceLanguageSearch
|
||||
: controller.targetLanguageSearch,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import 'dart:developer';
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/utils/any_state_holder.dart';
|
||||
import 'package:fluffychat/pangea/widgets/common_widgets/overlay_container.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
|
@ -22,7 +20,6 @@ class OverlayUtil {
|
|||
required BuildContext context,
|
||||
required Widget child,
|
||||
required String transformTargetId,
|
||||
// Size? size,
|
||||
double? width,
|
||||
double? height,
|
||||
Offset? offset,
|
||||
|
|
@ -63,13 +60,13 @@ class OverlayUtil {
|
|||
child: (position != OverlayPositionEnum.transform)
|
||||
? child
|
||||
: CompositedTransformFollower(
|
||||
targetAnchor: targetAnchor ?? Alignment.topLeft,
|
||||
followerAnchor: followerAnchor ?? Alignment.topLeft,
|
||||
targetAnchor: targetAnchor ?? Alignment.topCenter,
|
||||
followerAnchor:
|
||||
followerAnchor ?? Alignment.bottomCenter,
|
||||
link: MatrixState.pAnyState
|
||||
.layerLinkAndKey(transformTargetId)
|
||||
.link,
|
||||
showWhenUnlinked: false,
|
||||
offset: offset ?? Offset.zero,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
|
|
@ -103,11 +100,6 @@ class OverlayUtil {
|
|||
return;
|
||||
}
|
||||
|
||||
final Offset cardOffset = _calculateCardOffset(
|
||||
cardSize: cardSize,
|
||||
transformTargetContext: layerLinkAndKey.key.currentContext!,
|
||||
);
|
||||
|
||||
final Widget child = Material(
|
||||
borderOnForeground: false,
|
||||
color: Colors.transparent,
|
||||
|
|
@ -124,7 +116,6 @@ class OverlayUtil {
|
|||
width: cardSize.width,
|
||||
height: cardSize.height,
|
||||
transformTargetId: transformTargetId,
|
||||
offset: cardOffset,
|
||||
backDropToDismiss: backDropToDismiss,
|
||||
borderColor: borderColor,
|
||||
closePrevOverlay: closePrevOverlay,
|
||||
|
|
@ -135,73 +126,73 @@ class OverlayUtil {
|
|||
}
|
||||
}
|
||||
|
||||
/// calculates the card offset relative to the target
|
||||
/// identified by [transformTargetKey]
|
||||
static Offset _calculateCardOffset({
|
||||
required Size cardSize,
|
||||
required BuildContext transformTargetContext,
|
||||
final double minPadding = 10.0,
|
||||
}) {
|
||||
// debugger(when: kDebugMode);
|
||||
//Note: assumes overlay in chatview
|
||||
final OverlayConstraints constraints =
|
||||
ChatViewConstraints(transformTargetContext);
|
||||
// /// calculates the card offset relative to the target
|
||||
// /// identified by [transformTargetKey]
|
||||
// static Offset _calculateCardOffset({
|
||||
// required Size cardSize,
|
||||
// required BuildContext transformTargetContext,
|
||||
// final double minPadding = 10.0,
|
||||
// }) {
|
||||
// // debugger(when: kDebugMode);
|
||||
// //Note: assumes overlay in chatview
|
||||
// final OverlayConstraints constraints =
|
||||
// ChatViewConstraints(transformTargetContext);
|
||||
|
||||
final RenderObject? targetRenderBox =
|
||||
transformTargetContext.findRenderObject();
|
||||
if (targetRenderBox == null) return Offset.zero;
|
||||
final Offset transformTargetOffset =
|
||||
(targetRenderBox as RenderBox).localToGlobal(Offset.zero);
|
||||
final Size transformTargetSize = targetRenderBox.size;
|
||||
// final RenderObject? targetRenderBox =
|
||||
// transformTargetContext.findRenderObject();
|
||||
// if (targetRenderBox == null) return Offset.zero;
|
||||
// final Offset transformTargetOffset =
|
||||
// (targetRenderBox as RenderBox).localToGlobal(Offset.zero);
|
||||
// final Size transformTargetSize = targetRenderBox.size;
|
||||
|
||||
// ideally horizontally centered on target
|
||||
double dx = transformTargetSize.width / 2 - cardSize.width / 2;
|
||||
// make sure it's not off the left edge of the screen
|
||||
// if transformTargetOffset.dx + dc < constraints.x0 + minPadding
|
||||
// // ideally horizontally centered on target
|
||||
// double dx = transformTargetSize.width / 2 - cardSize.width / 2;
|
||||
// // make sure it's not off the left edge of the screen
|
||||
// // if transformTargetOffset.dx + dc < constraints.x0 + minPadding
|
||||
|
||||
if (transformTargetOffset.dx + dx < minPadding + constraints.x0) {
|
||||
debugPrint("setting dx");
|
||||
dx = minPadding + constraints.x0 - transformTargetOffset.dx;
|
||||
}
|
||||
// make sure it's not off the right edge of the screen
|
||||
if (transformTargetOffset.dx + dx + cardSize.width + minPadding >
|
||||
constraints.x1) {
|
||||
dx = constraints.x1 -
|
||||
transformTargetOffset.dx -
|
||||
cardSize.width -
|
||||
minPadding;
|
||||
}
|
||||
// if (transformTargetOffset.dx + dx < minPadding + constraints.x0) {
|
||||
// debugPrint("setting dx");
|
||||
// dx = minPadding + constraints.x0 - transformTargetOffset.dx;
|
||||
// }
|
||||
// // make sure it's not off the right edge of the screen
|
||||
// if (transformTargetOffset.dx + dx + cardSize.width + minPadding >
|
||||
// constraints.x1) {
|
||||
// dx = constraints.x1 -
|
||||
// transformTargetOffset.dx -
|
||||
// cardSize.width -
|
||||
// minPadding;
|
||||
// }
|
||||
|
||||
// if there's more room above target,
|
||||
// put the card there
|
||||
// else,
|
||||
// put it below
|
||||
// debugPrint(
|
||||
// "transformTargetOffset.dx ${transformTargetOffset.dx} transformTargetOffset.dy ${transformTargetOffset.dy}");
|
||||
// debugPrint(
|
||||
// "transformTargetSize.width ${transformTargetSize.width} transformTargetSize.height ${transformTargetSize.height}");
|
||||
double dy = transformTargetOffset.dy >
|
||||
constraints.y1 -
|
||||
transformTargetOffset.dy -
|
||||
transformTargetSize.height
|
||||
? -cardSize.height - minPadding
|
||||
: transformTargetSize.height + minPadding;
|
||||
// make sure it's not off the top edge of the screen
|
||||
if (dy < minPadding + constraints.y0 - transformTargetOffset.dy) {
|
||||
dy = minPadding + constraints.y0 - transformTargetOffset.dy;
|
||||
}
|
||||
// make sure it's not off the bottom edge of the screen
|
||||
if (transformTargetOffset.dy + dy + cardSize.height + minPadding >
|
||||
constraints.y1) {
|
||||
dy = constraints.y1 -
|
||||
transformTargetOffset.dy -
|
||||
cardSize.height -
|
||||
minPadding;
|
||||
}
|
||||
// debugPrint("dx $dx dy $dy");
|
||||
// // if there's more room above target,
|
||||
// // put the card there
|
||||
// // else,
|
||||
// // put it below
|
||||
// // debugPrint(
|
||||
// // "transformTargetOffset.dx ${transformTargetOffset.dx} transformTargetOffset.dy ${transformTargetOffset.dy}");
|
||||
// // debugPrint(
|
||||
// // "transformTargetSize.width ${transformTargetSize.width} transformTargetSize.height ${transformTargetSize.height}");
|
||||
// double dy = transformTargetOffset.dy >
|
||||
// constraints.y1 -
|
||||
// transformTargetOffset.dy -
|
||||
// transformTargetSize.height
|
||||
// ? -cardSize.height - minPadding
|
||||
// : transformTargetSize.height + minPadding;
|
||||
// // make sure it's not off the top edge of the screen
|
||||
// if (dy < minPadding + constraints.y0 - transformTargetOffset.dy) {
|
||||
// dy = minPadding + constraints.y0 - transformTargetOffset.dy;
|
||||
// }
|
||||
// // make sure it's not off the bottom edge of the screen
|
||||
// if (transformTargetOffset.dy + dy + cardSize.height + minPadding >
|
||||
// constraints.y1) {
|
||||
// dy = constraints.y1 -
|
||||
// transformTargetOffset.dy -
|
||||
// cardSize.height -
|
||||
// minPadding;
|
||||
// }
|
||||
// // debugPrint("dx $dx dy $dy");
|
||||
|
||||
return Offset(dx, dy);
|
||||
}
|
||||
// return Offset(dx, dy);
|
||||
// }
|
||||
|
||||
static bool get isOverlayOpen => MatrixState.pAnyState.entries.isNotEmpty;
|
||||
}
|
||||
|
|
@ -250,48 +241,48 @@ class TransparentBackdrop extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
/// global coordinates that the overlay should stay inside
|
||||
abstract class OverlayConstraints {
|
||||
late double x0;
|
||||
late double y0;
|
||||
late double x1;
|
||||
late double y1;
|
||||
}
|
||||
// /// global coordinates that the overlay should stay inside
|
||||
// abstract class OverlayConstraints {
|
||||
// late double x0;
|
||||
// late double y0;
|
||||
// late double x1;
|
||||
// late double y1;
|
||||
// }
|
||||
|
||||
class ChatViewConstraints implements OverlayConstraints {
|
||||
@override
|
||||
late double x0;
|
||||
@override
|
||||
late double y0;
|
||||
@override
|
||||
late double x1;
|
||||
@override
|
||||
late double y1;
|
||||
// class ChatViewConstraints implements OverlayConstraints {
|
||||
// @override
|
||||
// late double x0;
|
||||
// @override
|
||||
// late double y0;
|
||||
// @override
|
||||
// late double x1;
|
||||
// @override
|
||||
// late double y1;
|
||||
|
||||
ChatViewConstraints(BuildContext context) {
|
||||
final MediaQueryData mediaQueryData =
|
||||
MediaQuery.of(Scaffold.of(context).context);
|
||||
final bool isColumnMode = FluffyThemes.isColumnMode(context);
|
||||
// ChatViewConstraints(BuildContext context) {
|
||||
// final MediaQueryData mediaQueryData =
|
||||
// MediaQuery.of(Scaffold.of(context).context);
|
||||
// final bool isColumnMode = FluffyThemes.isColumnMode(context);
|
||||
|
||||
x0 = isColumnMode
|
||||
? AppConfig.columnWidth + 70.0
|
||||
: max(mediaQueryData.viewPadding.left, mediaQueryData.viewInsets.left);
|
||||
y0 = max(mediaQueryData.viewPadding.top, mediaQueryData.viewInsets.top);
|
||||
x1 = mediaQueryData.size.width -
|
||||
max(mediaQueryData.viewPadding.right, mediaQueryData.viewInsets.right);
|
||||
y1 = mediaQueryData.size.height -
|
||||
max(
|
||||
mediaQueryData.viewPadding.bottom,
|
||||
mediaQueryData.viewInsets.bottom,
|
||||
);
|
||||
// x0 = isColumnMode
|
||||
// ? AppConfig.columnWidth + 70.0
|
||||
// : max(mediaQueryData.viewPadding.left, mediaQueryData.viewInsets.left);
|
||||
// y0 = max(mediaQueryData.viewPadding.top, mediaQueryData.viewInsets.top);
|
||||
// x1 = mediaQueryData.size.width -
|
||||
// max(mediaQueryData.viewPadding.right, mediaQueryData.viewInsets.right);
|
||||
// y1 = mediaQueryData.size.height -
|
||||
// max(
|
||||
// mediaQueryData.viewPadding.bottom,
|
||||
// mediaQueryData.viewInsets.bottom,
|
||||
// );
|
||||
|
||||
// https://medium.com/flutter-community/a-flutter-guide-to-visual-overlap-padding-viewpadding-and-viewinsets-a63e214be6e8
|
||||
// debugPrint(
|
||||
// "viewInsets ${mediaQueryData.viewInsets.left} ${mediaQueryData.viewInsets.top} ${mediaQueryData.viewInsets.right} ${mediaQueryData.viewInsets.bottom}");
|
||||
// debugPrint(
|
||||
// "padding ${mediaQueryData.padding.left} ${mediaQueryData.padding.top} ${mediaQueryData.padding.right} ${mediaQueryData.padding.bottom}");
|
||||
// debugPrint(
|
||||
// "viewPadding ${mediaQueryData.viewPadding.left} ${mediaQueryData.viewPadding.top} ${mediaQueryData.viewPadding.right} ${mediaQueryData.viewPadding.bottom}");
|
||||
// debugPrint("chatViewConstraints x0: $x0 y0: $y0 x1: $x1 y1: $y1");
|
||||
}
|
||||
}
|
||||
// // https://medium.com/flutter-community/a-flutter-guide-to-visual-overlap-padding-viewpadding-and-viewinsets-a63e214be6e8
|
||||
// // debugPrint(
|
||||
// // "viewInsets ${mediaQueryData.viewInsets.left} ${mediaQueryData.viewInsets.top} ${mediaQueryData.viewInsets.right} ${mediaQueryData.viewInsets.bottom}");
|
||||
// // debugPrint(
|
||||
// // "padding ${mediaQueryData.padding.left} ${mediaQueryData.padding.top} ${mediaQueryData.padding.right} ${mediaQueryData.padding.bottom}");
|
||||
// // debugPrint(
|
||||
// // "viewPadding ${mediaQueryData.viewPadding.left} ${mediaQueryData.viewPadding.top} ${mediaQueryData.viewPadding.right} ${mediaQueryData.viewPadding.bottom}");
|
||||
// // debugPrint("chatViewConstraints x0: $x0 y0: $y0 x1: $x1 y1: $y1");
|
||||
// }
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -245,6 +245,7 @@ class WordMatchContent extends StatelessWidget {
|
|||
controller: scrollController,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// const SizedBox(height: 10.0),
|
||||
// if (matchCopy.description != null)
|
||||
|
|
|
|||
|
|
@ -231,6 +231,10 @@ class MessagePracticeActivityCardState extends State<PracticeActivityCard> {
|
|||
return;
|
||||
}
|
||||
|
||||
// clear the current activity and record
|
||||
currentActivity = null;
|
||||
currentCompletionRecord = null;
|
||||
|
||||
_fetchNewActivity(
|
||||
ActivityQualityFeedback(
|
||||
feedbackText: feedback,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ Future<void> pLanguageDialog(
|
|||
setState(() => selectedSourceLanguage = p0),
|
||||
initialLanguage: selectedSourceLanguage,
|
||||
languages: pangeaController.pLanguageStore.baseOptions,
|
||||
isL2List: false,
|
||||
),
|
||||
PQuestionContainer(
|
||||
title: L10n.of(parentContext)!.whatLanguageYouWantToLearn,
|
||||
|
|
@ -72,6 +73,7 @@ Future<void> pLanguageDialog(
|
|||
setState(() => selectedTargetLanguage = p0),
|
||||
initialLanguage: selectedTargetLanguage,
|
||||
languages: pangeaController.pLanguageStore.targetOptions,
|
||||
isL2List: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
// Flutter imports:
|
||||
|
||||
import 'package:fluffychat/pangea/enum/l2_support_enum.dart';
|
||||
import 'package:fluffychat/pangea/models/language_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
|
@ -10,6 +11,7 @@ class PLanguageDropdown extends StatefulWidget {
|
|||
final LanguageModel initialLanguage;
|
||||
final Function(LanguageModel) onChange;
|
||||
final bool showMultilingual;
|
||||
final bool isL2List;
|
||||
|
||||
const PLanguageDropdown({
|
||||
super.key,
|
||||
|
|
@ -17,6 +19,7 @@ class PLanguageDropdown extends StatefulWidget {
|
|||
required this.onChange,
|
||||
required this.initialLanguage,
|
||||
this.showMultilingual = false,
|
||||
required this.isL2List,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -98,6 +101,7 @@ class _PLanguageDropdownState extends State<PLanguageDropdown> {
|
|||
value: LanguageModel.multiLingual(context),
|
||||
child: LanguageDropDownEntry(
|
||||
languageModel: LanguageModel.multiLingual(context),
|
||||
isL2List: widget.isL2List,
|
||||
),
|
||||
),
|
||||
...sortedLanguages.map(
|
||||
|
|
@ -105,6 +109,7 @@ class _PLanguageDropdownState extends State<PLanguageDropdown> {
|
|||
value: languageModel,
|
||||
child: LanguageDropDownEntry(
|
||||
languageModel: languageModel,
|
||||
isL2List: widget.isL2List,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -118,9 +123,11 @@ class _PLanguageDropdownState extends State<PLanguageDropdown> {
|
|||
|
||||
class LanguageDropDownEntry extends StatelessWidget {
|
||||
final LanguageModel languageModel;
|
||||
final bool isL2List;
|
||||
const LanguageDropDownEntry({
|
||||
super.key,
|
||||
required this.languageModel,
|
||||
required this.isL2List,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -144,6 +151,9 @@ class LanguageDropDownEntry extends StatelessWidget {
|
|||
overflow: TextOverflow.clip,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
if (isL2List && languageModel.l2Support != L2SupportEnum.full)
|
||||
languageModel.l2Support.toBadge(context),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ description: Learn a language while texting your friends.
|
|||
# Pangea#
|
||||
publish_to: none
|
||||
# On version bump also increase the build number for F-Droid
|
||||
version: 1.21.4+3539
|
||||
version: 1.21.4+3540
|
||||
|
||||
environment:
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue