chore: reload info in word card in vocab details after submitting token feedback
This commit is contained in:
parent
6e3c6bcb2f
commit
257fb465be
10 changed files with 236 additions and 301 deletions
|
|
@ -18,9 +18,13 @@ import 'package:fluffychat/pangea/analytics_summary/learning_progress_indicators
|
|||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart';
|
||||
import 'package:fluffychat/pangea/morphs/default_morph_mapping.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_models.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_repo.dart';
|
||||
import 'package:fluffychat/pangea/token_info_feedback/show_token_feedback_dialog.dart';
|
||||
import 'package:fluffychat/pangea/token_info_feedback/token_info_feedback_request.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class ConstructAnalyticsView extends StatefulWidget {
|
||||
|
|
@ -49,6 +53,7 @@ class ConstructAnalyticsViewState extends State<ConstructAnalyticsView> {
|
|||
FocusNode searchFocusNode = FocusNode();
|
||||
ConstructLevelEnum? selectedConstructLevel;
|
||||
StreamSubscription<AnalyticsStreamUpdate>? _constructUpdateSub;
|
||||
final ValueNotifier<int> reloadNotifier = ValueNotifier<int>(0);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
|
@ -72,6 +77,7 @@ class ConstructAnalyticsViewState extends State<ConstructAnalyticsView> {
|
|||
searchController.dispose();
|
||||
_constructUpdateSub?.cancel();
|
||||
searchFocusNode.dispose();
|
||||
reloadNotifier.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
|
@ -162,6 +168,29 @@ class ConstructAnalyticsViewState extends State<ConstructAnalyticsView> {
|
|||
});
|
||||
}
|
||||
|
||||
Future<void> onFlagTokenInfo(
|
||||
PangeaToken token,
|
||||
LemmaInfoResponse lemmaInfo,
|
||||
String phonetics,
|
||||
) async {
|
||||
final requestData = TokenInfoFeedbackRequestData(
|
||||
userId: Matrix.of(context).client.userID!,
|
||||
detectedLanguage: MatrixState.pangeaController.userController.userL2Code!,
|
||||
tokens: [token],
|
||||
selectedToken: 0,
|
||||
wordCardL1: MatrixState.pangeaController.userController.userL1Code!,
|
||||
lemmaInfo: lemmaInfo,
|
||||
phonetics: phonetics,
|
||||
);
|
||||
|
||||
await TokenFeedbackUtil.showTokenFeedbackDialog(
|
||||
context,
|
||||
requestData: requestData,
|
||||
langCode: MatrixState.pangeaController.userController.userL2Code!,
|
||||
onUpdated: () => reloadNotifier.value++,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
|
@ -182,7 +211,10 @@ class ConstructAnalyticsViewState extends State<ConstructAnalyticsView> {
|
|||
: MorphDetailsView(constructId: widget.construct!)
|
||||
: widget.construct == null
|
||||
? VocabAnalyticsListView(controller: this)
|
||||
: VocabDetailsView(constructId: widget.construct!),
|
||||
: VocabDetailsView(
|
||||
constructId: widget.construct!,
|
||||
controller: this,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:collection/collection.dart';
|
||||
|
||||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_usage_content.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/construct_xp_progress_bar.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/word_text_with_audio_button.dart';
|
||||
|
|
@ -12,8 +13,6 @@ import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
|||
import 'package:fluffychat/pangea/events/models/pangea_token_text_model.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart';
|
||||
import 'package:fluffychat/pangea/token_info_feedback/show_token_feedback_dialog.dart';
|
||||
import 'package:fluffychat/pangea/token_info_feedback/token_info_feedback_request.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/word_card/word_zoom_widget.dart';
|
||||
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
|
||||
import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
||||
|
|
@ -23,10 +22,12 @@ import 'package:fluffychat/widgets/matrix.dart';
|
|||
/// Displays information about selected lemma, and its usage
|
||||
class VocabDetailsView extends StatelessWidget {
|
||||
final ConstructIdentifier constructId;
|
||||
final ConstructAnalyticsViewState controller;
|
||||
|
||||
const VocabDetailsView({
|
||||
super.key,
|
||||
required this.constructId,
|
||||
required this.controller,
|
||||
});
|
||||
|
||||
Future<void> _blockLemma(BuildContext context) async {
|
||||
|
|
@ -93,27 +94,12 @@ class VocabDetailsView extends StatelessWidget {
|
|||
MatrixState.pangeaController.userController.userL2Code!,
|
||||
construct: constructId,
|
||||
onClose: Navigator.of(context).pop,
|
||||
onFlagTokenInfo:
|
||||
(LemmaInfoResponse lemmaInfo, String phonetics) {
|
||||
final requestData = TokenInfoFeedbackRequestData(
|
||||
userId: Matrix.of(context).client.userID!,
|
||||
detectedLanguage: MatrixState
|
||||
.pangeaController.userController.userL2Code!,
|
||||
tokens: [token],
|
||||
selectedToken: 0,
|
||||
wordCardL1: MatrixState
|
||||
.pangeaController.userController.userL1Code!,
|
||||
lemmaInfo: lemmaInfo,
|
||||
phonetics: phonetics,
|
||||
);
|
||||
|
||||
TokenFeedbackUtil.showTokenFeedbackDialog(
|
||||
context,
|
||||
requestData: requestData,
|
||||
langCode: MatrixState
|
||||
.pangeaController.userController.userL2Code!,
|
||||
);
|
||||
},
|
||||
onFlagTokenInfo: (
|
||||
LemmaInfoResponse lemmaInfo,
|
||||
String phonetics,
|
||||
) =>
|
||||
controller.onFlagTokenInfo(token, lemmaInfo, phonetics),
|
||||
reloadNotifier: controller.reloadNotifier,
|
||||
maxWidth: double.infinity,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import 'package:shimmer/shimmer.dart';
|
|||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics_data/analytics_updater_mixin.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/async_state.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/shimmer_background.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_meaning_builder.dart';
|
||||
|
|
@ -49,35 +50,15 @@ class LemmaHighlightEmojiRowState extends State<LemmaHighlightEmojiRow>
|
|||
constructId: widget.cId,
|
||||
messageInfo: widget.messageInfo,
|
||||
builder: (context, controller) {
|
||||
if (controller.error != null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
final emojis = controller.lemmaInfo?.emoji;
|
||||
return SizedBox(
|
||||
height: 70.0,
|
||||
child: Row(
|
||||
spacing: 4.0,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: emojis == null || emojis.isEmpty
|
||||
? List.generate(
|
||||
3,
|
||||
(_) => Shimmer.fromColors(
|
||||
baseColor: Colors.transparent,
|
||||
highlightColor:
|
||||
Theme.of(context).colorScheme.primary.withAlpha(70),
|
||||
child: Container(
|
||||
height: 55.0,
|
||||
width: 55.0,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
borderRadius:
|
||||
BorderRadius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: emojis.map(
|
||||
return switch (controller.state) {
|
||||
AsyncError() => const SizedBox.shrink(),
|
||||
AsyncLoaded(value: final lemmaInfo) => SizedBox(
|
||||
height: 70.0,
|
||||
child: Row(
|
||||
spacing: 4.0,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
...lemmaInfo.emoji.map(
|
||||
(emoji) {
|
||||
final targetId = "${widget.targetId}-$emoji";
|
||||
return EmojiChoiceItem(
|
||||
|
|
@ -94,9 +75,35 @@ class LemmaHighlightEmojiRowState extends State<LemmaHighlightEmojiRow>
|
|||
enabled: widget.enabled,
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
),
|
||||
);
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
_ => SizedBox(
|
||||
height: 70.0,
|
||||
child: Row(
|
||||
spacing: 4.0,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: List.generate(
|
||||
3,
|
||||
(_) => Shimmer.fromColors(
|
||||
baseColor: Colors.transparent,
|
||||
highlightColor:
|
||||
Theme.of(context).colorScheme.primary.withAlpha(70),
|
||||
child: Container(
|
||||
height: 55.0,
|
||||
width: 55.0,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
borderRadius:
|
||||
BorderRadius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,29 +8,11 @@ import 'package:fluffychat/pangea/lemmas/lemma_info_request.dart';
|
|||
import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class _LemmaMeaningLoader extends AsyncLoader<LemmaInfoResponse> {
|
||||
final LemmaInfoRequest request;
|
||||
_LemmaMeaningLoader(this.request) : super();
|
||||
|
||||
@override
|
||||
Future<LemmaInfoResponse> fetch() async {
|
||||
final result = await LemmaInfoRepo.get(
|
||||
MatrixState.pangeaController.userController.accessToken,
|
||||
request,
|
||||
);
|
||||
|
||||
if (result.isError) {
|
||||
throw result.asError!.error;
|
||||
}
|
||||
|
||||
return result.asValue!.value;
|
||||
}
|
||||
}
|
||||
|
||||
class LemmaMeaningBuilder extends StatefulWidget {
|
||||
final String langCode;
|
||||
final ConstructIdentifier constructId;
|
||||
final Map<String, dynamic> messageInfo;
|
||||
final ValueNotifier<int>? reloadNotifier;
|
||||
|
||||
final Widget Function(
|
||||
BuildContext context,
|
||||
|
|
@ -43,6 +25,7 @@ class LemmaMeaningBuilder extends StatefulWidget {
|
|||
required this.constructId,
|
||||
required this.builder,
|
||||
required this.messageInfo,
|
||||
this.reloadNotifier,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -50,12 +33,14 @@ class LemmaMeaningBuilder extends StatefulWidget {
|
|||
}
|
||||
|
||||
class LemmaMeaningBuilderState extends State<LemmaMeaningBuilder> {
|
||||
late _LemmaMeaningLoader _loader;
|
||||
final ValueNotifier<AsyncState<LemmaInfoResponse>> _loader =
|
||||
ValueNotifier(const AsyncState.idle());
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_reload();
|
||||
_load();
|
||||
widget.reloadNotifier?.addListener(_load);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -63,24 +48,22 @@ class LemmaMeaningBuilderState extends State<LemmaMeaningBuilder> {
|
|||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.constructId != widget.constructId ||
|
||||
oldWidget.langCode != widget.langCode) {
|
||||
_loader.dispose();
|
||||
_reload();
|
||||
_load();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
widget.reloadNotifier?.removeListener(_load);
|
||||
_loader.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
bool get isLoading => _loader.isLoading;
|
||||
bool get isError => _loader.isError;
|
||||
|
||||
Object? get error =>
|
||||
isError ? (_loader.state.value as AsyncError).error : null;
|
||||
|
||||
LemmaInfoResponse? get lemmaInfo => _loader.value;
|
||||
AsyncState<LemmaInfoResponse> get state => _loader.value;
|
||||
bool get isError => _loader.value is AsyncError;
|
||||
bool get isLoaded => _loader.value is AsyncLoaded;
|
||||
LemmaInfoResponse? get lemmaInfo =>
|
||||
isLoaded ? (_loader.value as AsyncLoaded<LemmaInfoResponse>).value : null;
|
||||
|
||||
LemmaInfoRequest get _request => LemmaInfoRequest(
|
||||
lemma: widget.constructId.lemma,
|
||||
|
|
@ -91,15 +74,23 @@ class LemmaMeaningBuilderState extends State<LemmaMeaningBuilder> {
|
|||
messageInfo: widget.messageInfo,
|
||||
);
|
||||
|
||||
void _reload() {
|
||||
_loader = _LemmaMeaningLoader(_request);
|
||||
_loader.load();
|
||||
Future<void> _load() async {
|
||||
_loader.value = const AsyncState.loading();
|
||||
final result = await LemmaInfoRepo.get(
|
||||
MatrixState.pangeaController.userController.accessToken,
|
||||
_request,
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
result.isError
|
||||
? _loader.value = AsyncState.error(result.asError!.error)
|
||||
: _loader.value = AsyncState.loaded(result.asValue!.value);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: _loader.state,
|
||||
valueListenable: _loader,
|
||||
builder: (context, _, __) => widget.builder(
|
||||
context,
|
||||
this,
|
||||
|
|
|
|||
|
|
@ -1,77 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/text_loading_shimmer.dart';
|
||||
import 'package:fluffychat/pangea/common/network/requests.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/error_indicator.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_meaning_builder.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class LemmaMeaningWidget extends StatelessWidget {
|
||||
final ConstructIdentifier constructId;
|
||||
final TextStyle? style;
|
||||
final InlineSpan? leading;
|
||||
final Map<String, dynamic> messageInfo;
|
||||
|
||||
const LemmaMeaningWidget({
|
||||
super.key,
|
||||
required this.constructId,
|
||||
required this.messageInfo,
|
||||
this.style,
|
||||
this.leading,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LemmaMeaningBuilder(
|
||||
langCode: MatrixState.pangeaController.userController.userL2!.langCode,
|
||||
constructId: constructId,
|
||||
messageInfo: messageInfo,
|
||||
builder: (context, controller) {
|
||||
if (controller.isLoading) {
|
||||
return const TextLoadingShimmer();
|
||||
}
|
||||
|
||||
if (controller.error != null) {
|
||||
if (controller.error is UnsubscribedException) {
|
||||
return ErrorIndicator(
|
||||
message: L10n.of(context).subscribeToUnlockDefinitions,
|
||||
style: style,
|
||||
onTap: () {
|
||||
MatrixState.pangeaController.subscriptionController
|
||||
.showPaywall(context);
|
||||
},
|
||||
);
|
||||
}
|
||||
return ErrorIndicator(
|
||||
message: L10n.of(context).errorFetchingDefinition,
|
||||
style: style,
|
||||
);
|
||||
}
|
||||
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Flexible(
|
||||
child: RichText(
|
||||
textAlign: leading == null ? TextAlign.center : TextAlign.start,
|
||||
text: TextSpan(
|
||||
style: style,
|
||||
children: [
|
||||
if (leading != null) leading!,
|
||||
if (leading != null)
|
||||
const WidgetSpan(child: SizedBox(width: 6.0)),
|
||||
TextSpan(
|
||||
text: controller.lemmaInfo?.meaning,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,29 +8,10 @@ import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_
|
|||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'phonetic_transcription_repo.dart';
|
||||
|
||||
class _TranscriptLoader extends AsyncLoader<String> {
|
||||
final PhoneticTranscriptionRequest request;
|
||||
_TranscriptLoader(this.request) : super();
|
||||
|
||||
@override
|
||||
Future<String> fetch() async {
|
||||
final resp = await PhoneticTranscriptionRepo.get(
|
||||
MatrixState.pangeaController.userController.accessToken,
|
||||
request,
|
||||
);
|
||||
|
||||
if (resp.isError) {
|
||||
throw resp.asError!.error;
|
||||
}
|
||||
|
||||
return resp.asValue!.value.phoneticTranscriptionResult.phoneticTranscription
|
||||
.first.phoneticL1Transcription.content;
|
||||
}
|
||||
}
|
||||
|
||||
class PhoneticTranscriptionBuilder extends StatefulWidget {
|
||||
final LanguageModel textLanguage;
|
||||
final String text;
|
||||
final ValueNotifier<int>? reloadNotifier;
|
||||
|
||||
final Widget Function(
|
||||
BuildContext context,
|
||||
|
|
@ -42,6 +23,7 @@ class PhoneticTranscriptionBuilder extends StatefulWidget {
|
|||
required this.textLanguage,
|
||||
required this.text,
|
||||
required this.builder,
|
||||
this.reloadNotifier,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -51,12 +33,14 @@ class PhoneticTranscriptionBuilder extends StatefulWidget {
|
|||
|
||||
class PhoneticTranscriptionBuilderState
|
||||
extends State<PhoneticTranscriptionBuilder> {
|
||||
late _TranscriptLoader _loader;
|
||||
final ValueNotifier<AsyncState<String>> _loader =
|
||||
ValueNotifier(const AsyncState.idle());
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_reload();
|
||||
_load();
|
||||
widget.reloadNotifier?.addListener(_load);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -64,27 +48,24 @@ class PhoneticTranscriptionBuilderState
|
|||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.text != widget.text ||
|
||||
oldWidget.textLanguage != widget.textLanguage) {
|
||||
_loader.dispose();
|
||||
_reload();
|
||||
_load();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
widget.reloadNotifier?.removeListener(_load);
|
||||
_loader.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
bool get isLoading => _loader.isLoading;
|
||||
bool get isError => _loader.isError;
|
||||
AsyncState<String> get state => _loader.value;
|
||||
bool get isError => _loader.value is AsyncError;
|
||||
bool get isLoaded => _loader.value is AsyncLoaded;
|
||||
String? get transcription =>
|
||||
isLoaded ? (_loader.value as AsyncLoaded<String>).value : null;
|
||||
|
||||
Object? get error =>
|
||||
isError ? (_loader.state.value as AsyncError).error : null;
|
||||
|
||||
String? get transcription => _loader.value;
|
||||
|
||||
PhoneticTranscriptionRequest get _transcriptRequest =>
|
||||
PhoneticTranscriptionRequest(
|
||||
PhoneticTranscriptionRequest get _request => PhoneticTranscriptionRequest(
|
||||
arc: LanguageArc(
|
||||
l1: MatrixState.pangeaController.userController.userL1!,
|
||||
l2: widget.textLanguage,
|
||||
|
|
@ -92,15 +73,26 @@ class PhoneticTranscriptionBuilderState
|
|||
content: PangeaTokenText.fromString(widget.text),
|
||||
);
|
||||
|
||||
void _reload() {
|
||||
_loader = _TranscriptLoader(_transcriptRequest);
|
||||
_loader.load();
|
||||
Future<void> _load() async {
|
||||
_loader.value = const AsyncState.loading();
|
||||
final resp = await PhoneticTranscriptionRepo.get(
|
||||
MatrixState.pangeaController.userController.accessToken,
|
||||
_request,
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
resp.isError
|
||||
? _loader.value = AsyncState.error(resp.asError!.error)
|
||||
: _loader.value = AsyncState.loaded(
|
||||
resp.asValue!.value.phoneticTranscriptionResult
|
||||
.phoneticTranscription.first.phoneticL1Transcription.content,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: _loader.state,
|
||||
valueListenable: _loader,
|
||||
builder: (context, _, __) => widget.builder(
|
||||
context,
|
||||
this,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/text_loading_shimmer.dart';
|
||||
import 'package:fluffychat/pangea/common/network/requests.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/async_state.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/error_indicator.dart';
|
||||
import 'package:fluffychat/pangea/languages/language_model.dart';
|
||||
import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_builder.dart';
|
||||
|
|
@ -22,6 +21,7 @@ class PhoneticTranscriptionWidget extends StatefulWidget {
|
|||
final int? maxLines;
|
||||
|
||||
final VoidCallback? onTranscriptionFetched;
|
||||
final ValueNotifier<int>? reloadNotifier;
|
||||
|
||||
const PhoneticTranscriptionWidget({
|
||||
super.key,
|
||||
|
|
@ -32,6 +32,7 @@ class PhoneticTranscriptionWidget extends StatefulWidget {
|
|||
this.iconColor,
|
||||
this.maxLines,
|
||||
this.onTranscriptionFetched,
|
||||
this.reloadNotifier,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -85,59 +86,58 @@ class _PhoneticTranscriptionWidgetState
|
|||
key: MatrixState.pAnyState.layerLinkAndKey(targetId).key,
|
||||
textLanguage: widget.textLanguage,
|
||||
text: widget.text,
|
||||
reloadNotifier: widget.reloadNotifier,
|
||||
builder: (context, controller) {
|
||||
if (controller.isError) {
|
||||
return controller.error is UnsubscribedException
|
||||
? ErrorIndicator(
|
||||
message: L10n.of(context)
|
||||
.subscribeToUnlockTranscriptions,
|
||||
onTap: () {
|
||||
MatrixState
|
||||
.pangeaController.subscriptionController
|
||||
.showPaywall(context);
|
||||
},
|
||||
)
|
||||
: ErrorIndicator(
|
||||
message:
|
||||
L10n.of(context).failedToFetchTranscription,
|
||||
);
|
||||
}
|
||||
|
||||
if (controller.isLoading ||
|
||||
controller.transcription == null) {
|
||||
return const TextLoadingShimmer(
|
||||
width: 125.0,
|
||||
height: 20.0,
|
||||
);
|
||||
}
|
||||
|
||||
return Row(
|
||||
spacing: 8.0,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
controller.transcription!,
|
||||
textScaler: TextScaler.noScaling,
|
||||
style: widget.style ??
|
||||
Theme.of(context).textTheme.bodyMedium,
|
||||
maxLines: widget.maxLines,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
return switch (controller.state) {
|
||||
AsyncError(error: final error) =>
|
||||
error is UnsubscribedException
|
||||
? ErrorIndicator(
|
||||
message: L10n.of(context)
|
||||
.subscribeToUnlockTranscriptions,
|
||||
onTap: () {
|
||||
MatrixState
|
||||
.pangeaController.subscriptionController
|
||||
.showPaywall(context);
|
||||
},
|
||||
)
|
||||
: ErrorIndicator(
|
||||
message:
|
||||
L10n.of(context).failedToFetchTranscription,
|
||||
),
|
||||
AsyncLoaded<String>(value: final transcription) => Row(
|
||||
spacing: 8.0,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
transcription,
|
||||
textScaler: TextScaler.noScaling,
|
||||
style: widget.style ??
|
||||
Theme.of(context).textTheme.bodyMedium,
|
||||
maxLines: widget.maxLines,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
Tooltip(
|
||||
message: _isPlaying
|
||||
? L10n.of(context).stop
|
||||
: L10n.of(context).playAudio,
|
||||
child: Icon(
|
||||
_isPlaying
|
||||
? Icons.pause_outlined
|
||||
: Icons.volume_up,
|
||||
size: widget.iconSize ?? 24,
|
||||
color: widget.iconColor ??
|
||||
Theme.of(context).iconTheme.color,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Tooltip(
|
||||
message: _isPlaying
|
||||
? L10n.of(context).stop
|
||||
: L10n.of(context).playAudio,
|
||||
child: Icon(
|
||||
_isPlaying ? Icons.pause_outlined : Icons.volume_up,
|
||||
size: widget.iconSize ?? 24,
|
||||
color: widget.iconColor ??
|
||||
Theme.of(context).iconTheme.color,
|
||||
),
|
||||
_ => const TextLoadingShimmer(
|
||||
width: 125.0,
|
||||
height: 20.0,
|
||||
),
|
||||
],
|
||||
);
|
||||
};
|
||||
},
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ class TokenFeedbackUtil {
|
|||
required TokenInfoFeedbackRequestData requestData,
|
||||
required String langCode,
|
||||
PangeaMessageEvent? event,
|
||||
VoidCallback? onUpdated,
|
||||
}) async {
|
||||
final resp = await showDialog(
|
||||
context: context,
|
||||
|
|
@ -23,6 +24,8 @@ class TokenFeedbackUtil {
|
|||
);
|
||||
|
||||
if (resp == null) return;
|
||||
|
||||
onUpdated?.call();
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/text_loading_shimmer.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/async_state.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/error_indicator.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_meaning_builder.dart';
|
||||
|
|
@ -12,6 +13,7 @@ class LemmaMeaningDisplay extends StatelessWidget {
|
|||
final ConstructIdentifier constructId;
|
||||
final String text;
|
||||
final Map<String, dynamic> messageInfo;
|
||||
final ValueNotifier<int>? reloadNotifier;
|
||||
|
||||
const LemmaMeaningDisplay({
|
||||
super.key,
|
||||
|
|
@ -19,6 +21,7 @@ class LemmaMeaningDisplay extends StatelessWidget {
|
|||
required this.constructId,
|
||||
required this.text,
|
||||
required this.messageInfo,
|
||||
this.reloadNotifier,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -27,53 +30,47 @@ class LemmaMeaningDisplay extends StatelessWidget {
|
|||
langCode: langCode,
|
||||
constructId: constructId,
|
||||
messageInfo: messageInfo,
|
||||
reloadNotifier: reloadNotifier,
|
||||
builder: (context, controller) {
|
||||
if (controller.isError) {
|
||||
return ErrorIndicator(
|
||||
message: L10n.of(context).errorFetchingDefinition,
|
||||
style: const TextStyle(fontSize: 14.0),
|
||||
);
|
||||
}
|
||||
|
||||
if (controller.isLoading || controller.lemmaInfo == null) {
|
||||
return const TextLoadingShimmer(
|
||||
width: 125.0,
|
||||
height: 20.0,
|
||||
);
|
||||
}
|
||||
|
||||
final pos = getGrammarCopy(
|
||||
category: "POS",
|
||||
lemma: constructId.category,
|
||||
context: context,
|
||||
) ??
|
||||
L10n.of(context).other;
|
||||
|
||||
return RichText(
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
style: DefaultTextStyle.of(context).style.copyWith(
|
||||
fontSize: 14.0,
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "${constructId.lemma} ($pos)",
|
||||
return switch (controller.state) {
|
||||
AsyncError() => ErrorIndicator(
|
||||
message: L10n.of(context).errorFetchingDefinition,
|
||||
style: const TextStyle(fontSize: 14.0),
|
||||
),
|
||||
AsyncLoaded(value: final lemmaInfo) => RichText(
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
style: DefaultTextStyle.of(context).style.copyWith(
|
||||
fontSize: 14.0,
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "${constructId.lemma} (${getGrammarCopy(
|
||||
category: "POS",
|
||||
lemma: constructId.category,
|
||||
context: context,
|
||||
) ?? L10n.of(context).other})",
|
||||
),
|
||||
const WidgetSpan(
|
||||
child: SizedBox(width: 8.0),
|
||||
),
|
||||
const TextSpan(text: ":"),
|
||||
const WidgetSpan(
|
||||
child: SizedBox(width: 8.0),
|
||||
),
|
||||
TextSpan(
|
||||
text: lemmaInfo.meaning,
|
||||
),
|
||||
],
|
||||
),
|
||||
const WidgetSpan(
|
||||
child: SizedBox(width: 8.0),
|
||||
),
|
||||
const TextSpan(text: ":"),
|
||||
const WidgetSpan(
|
||||
child: SizedBox(width: 8.0),
|
||||
),
|
||||
TextSpan(
|
||||
text: controller.lemmaInfo!.meaning,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
),
|
||||
_ => const TextLoadingShimmer(
|
||||
width: 125.0,
|
||||
height: 20.0,
|
||||
),
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class WordZoomWidget extends StatelessWidget {
|
|||
final bool enableEmojiSelection;
|
||||
final VoidCallback? onDismissNewWordOverlay;
|
||||
final Function(LemmaInfoResponse, String)? onFlagTokenInfo;
|
||||
final ValueNotifier<int>? reloadNotifier;
|
||||
final double? maxWidth;
|
||||
|
||||
const WordZoomWidget({
|
||||
|
|
@ -42,6 +43,7 @@ class WordZoomWidget extends StatelessWidget {
|
|||
this.enableEmojiSelection = true,
|
||||
this.onDismissNewWordOverlay,
|
||||
this.onFlagTokenInfo,
|
||||
this.reloadNotifier,
|
||||
this.maxWidth,
|
||||
});
|
||||
|
||||
|
|
@ -143,6 +145,7 @@ class WordZoomWidget extends StatelessWidget {
|
|||
style: const TextStyle(fontSize: 14.0),
|
||||
iconSize: 24.0,
|
||||
maxLines: 2,
|
||||
reloadNotifier: reloadNotifier,
|
||||
)
|
||||
: WordAudioButton(
|
||||
text: token.content,
|
||||
|
|
@ -161,6 +164,7 @@ class WordZoomWidget extends StatelessWidget {
|
|||
constructId: construct,
|
||||
text: token.content,
|
||||
messageInfo: event?.content ?? {},
|
||||
reloadNotifier: reloadNotifier,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue