forked from pndaza/tipitaka-pali
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor dict_content_view to separate files for dpd extra buttons sh…
…ow_declension_dialog.dart ... etc
- Loading branch information
Showing
10 changed files
with
876 additions
and
810 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
import 'dart:convert'; | ||
|
||
import 'package:flutter/material.dart'; | ||
import 'package:provider/provider.dart'; | ||
import 'package:tipitaka_pali/ui/screens/dictionary/controller/dictionary_controller.dart'; | ||
import 'package:tipitaka_pali/utils/platform_info.dart'; | ||
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||
import 'package:tipitaka_pali/utils/super_scripter_uni.dart'; | ||
|
||
import '../../../../business_logic/models/dpd_compound_family.dart'; | ||
import '../../../../services/prefs.dart'; | ||
|
||
showCompoundFamilyDialog(BuildContext context, int wordId) async { | ||
var dictionaryController = context.read<DictionaryController>(); | ||
List<DpdCompoundFamily>? compoundFamilies = | ||
await dictionaryController.getDpdCompoundFamilies(wordId); | ||
|
||
// prevent using context across asynch gaps | ||
if (!context.mounted) return; | ||
|
||
if (compoundFamilies == null || compoundFamilies.isEmpty) { | ||
// TODO not all words have root family, so need to show a 'install' dialog | ||
// only if the root family tables do not exist | ||
|
||
return; | ||
} | ||
|
||
debugPrint('Compound families count: ${compoundFamilies.length}'); | ||
if (!context.mounted) return; | ||
|
||
List<dynamic> jsonData = []; | ||
for (final compoundFamily in compoundFamilies) { | ||
jsonData.addAll(json.decode(compoundFamily.data)); | ||
} | ||
|
||
final DpdCompoundFamily first = compoundFamilies[0]; | ||
final count = compoundFamilies.fold(0, (sum, cf) => sum + cf.count); | ||
final isMobile = Mobile.isPhone(context); | ||
const insetPadding = 10.0; | ||
final word = first.word.replaceAll(RegExp(r" \d.*\$"), ''); | ||
|
||
final content = isMobile | ||
? SizedBox( | ||
width: MediaQuery.of(context).size.width - 2 * insetPadding, | ||
child: _getCompoundFamilyWidget(count, word, jsonData), | ||
) | ||
: Container( | ||
constraints: const BoxConstraints( | ||
maxHeight: 400, | ||
maxWidth: 800, | ||
), | ||
child: _getCompoundFamilyWidget(count, word, jsonData)); | ||
|
||
showDialog( | ||
context: context, | ||
builder: (context) => AlertDialog( | ||
title: Text(superscripterUni(first.word)), | ||
contentPadding: isMobile ? EdgeInsets.zero : null, | ||
insetPadding: isMobile ? const EdgeInsets.all(insetPadding) : null, | ||
content: content, | ||
actions: [ | ||
TextButton( | ||
onPressed: () => Navigator.pop(context), | ||
child: Text(AppLocalizations.of(context)!.ok)) | ||
], | ||
)); | ||
} | ||
|
||
Scrollbar _getCompoundFamilyWidget(count, word, jsonData) { | ||
final horizontal = ScrollController(); | ||
final vertical = ScrollController(); | ||
return Scrollbar( | ||
controller: vertical, | ||
thumbVisibility: true, | ||
trackVisibility: true, | ||
child: Scrollbar( | ||
controller: horizontal, | ||
thumbVisibility: true, | ||
trackVisibility: true, | ||
notificationPredicate: (notification) => notification.depth == 1, | ||
child: SingleChildScrollView( | ||
controller: vertical, | ||
child: SingleChildScrollView( | ||
controller: horizontal, | ||
scrollDirection: Axis.horizontal, | ||
child: Column( | ||
crossAxisAlignment: CrossAxisAlignment.start, | ||
children: [ | ||
_getCompoundFamilyHeader(count, word), | ||
_getCompoundFamilyTable(jsonData) | ||
], | ||
)), | ||
), | ||
), | ||
); | ||
} | ||
|
||
SelectableText _getCompoundFamilyHeader(count, word) { | ||
return SelectableText.rich( | ||
TextSpan(children: [ | ||
TextSpan( | ||
text: '$count', style: const TextStyle(fontWeight: FontWeight.bold)), | ||
const TextSpan(text: ' compounds which contain '), | ||
TextSpan( | ||
text: word, | ||
style: TextStyle( | ||
fontSize: Prefs.dictionaryFontSize.toDouble(), | ||
fontWeight: FontWeight.bold)), | ||
]), | ||
textAlign: TextAlign.left, | ||
); | ||
} | ||
|
||
Table _getCompoundFamilyTable(List<dynamic> jsonData) { | ||
return Table( | ||
border: TableBorder.all(), | ||
defaultColumnWidth: const IntrinsicColumnWidth(), | ||
children: jsonData.map((item) { | ||
return TableRow( | ||
children: [ | ||
TableCell( | ||
child: Padding( | ||
padding: const EdgeInsets.all(8.0), | ||
child: SelectableText( | ||
item[0], | ||
style: TextStyle( | ||
fontSize: Prefs.dictionaryFontSize.toDouble(), | ||
color: Colors.orange, | ||
fontWeight: FontWeight.bold), | ||
), | ||
), | ||
), | ||
TableCell( | ||
child: Padding( | ||
padding: const EdgeInsets.all(8.0), | ||
child: SelectableText( | ||
item[1], | ||
style: TextStyle( | ||
fontSize: Prefs.dictionaryFontSize.toDouble(), | ||
fontWeight: FontWeight.bold), | ||
), | ||
), | ||
), | ||
TableCell( | ||
child: Padding( | ||
padding: const EdgeInsets.all(8.0), | ||
child: SelectableText('${item[2]} ${item[3]}', | ||
style: | ||
TextStyle(fontSize: Prefs.dictionaryFontSize.toDouble())), | ||
), | ||
), | ||
], | ||
); | ||
}).toList(), | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
import 'dart:convert'; | ||
|
||
import 'package:collection/collection.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:provider/provider.dart'; | ||
import 'package:tipitaka_pali/business_logic/models/dpd_inflection.dart'; | ||
import 'package:tipitaka_pali/routes.dart'; | ||
import 'package:tipitaka_pali/services/prefs.dart'; | ||
import 'package:tipitaka_pali/ui/screens/dictionary/controller/dictionary_controller.dart'; | ||
import 'package:tipitaka_pali/ui/screens/settings/download_view.dart'; | ||
import 'package:tipitaka_pali/utils/platform_info.dart'; | ||
import 'package:tipitaka_pali/utils/super_scripter_uni.dart'; | ||
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||
|
||
showDeclensionDialog(BuildContext context, int wordId) async { | ||
var dictionaryController = context.read<DictionaryController>(); | ||
DpdInflection? inflection = | ||
await dictionaryController.getDpdInflection(wordId); | ||
|
||
// Prevent using context across async gaps | ||
if (!context.mounted) return; | ||
|
||
// Handle case where no inflection data is found | ||
if (inflection == null) { | ||
bool? shouldNavigate = await showDialog<bool>( | ||
context: context, | ||
builder: (dialogContext) => AlertDialog( | ||
title: Text(AppLocalizations.of(context)!.inflectionNoDataTitle), | ||
content: Text(AppLocalizations.of(context)!.inflectionNoDataMessage), | ||
actions: [ | ||
TextButton( | ||
onPressed: () => Navigator.of(dialogContext).pop(false), | ||
child: Text(AppLocalizations.of(context)!.close), | ||
), | ||
], | ||
), | ||
); | ||
|
||
if (shouldNavigate == true) { | ||
if (!context.mounted) return; | ||
final route = | ||
MaterialPageRoute(builder: (context) => const DownloadView()); | ||
NestedNavigationHelper.goto( | ||
context: context, route: route, navkey: dictionaryNavigationKey); | ||
} | ||
|
||
return; | ||
} | ||
|
||
debugPrint('Inflection: $inflection'); | ||
|
||
String data = await DefaultAssetBundle.of(context) | ||
.loadString("assets/inflectionTemplates.json"); | ||
List inflectionTemplates = jsonDecode(data); | ||
final template = inflectionTemplates | ||
.firstWhereOrNull((map) => map['pattern'] == inflection.pattern); | ||
|
||
if (template == null) { | ||
debugPrint('Could not find template...'); | ||
return; | ||
} | ||
|
||
debugPrint('Template: $template'); | ||
|
||
// Prepare the table rows from the template data | ||
List<TableRow> rows = | ||
template['data'].asMap().entries.map<TableRow>((rowEntry) { | ||
int rowIndex = rowEntry.key; | ||
List<List<String>> row = (rowEntry.value as List) | ||
.map((e) => (e as List).map((item) => item as String).toList()) | ||
.toList(); | ||
|
||
return TableRow( | ||
children: row | ||
.asMap() | ||
.entries | ||
.map<Padding?>((entry) { | ||
int colIndex = entry.key; | ||
List<String> cell = entry.value; | ||
if (colIndex == 0) { | ||
return Padding( | ||
padding: const EdgeInsets.all(8.0), | ||
child: SelectableText(cell[0], | ||
style: const TextStyle( | ||
fontWeight: FontWeight.w600, color: Colors.orange)), | ||
); | ||
} | ||
if (colIndex % 2 != 1) { | ||
return null; | ||
} | ||
List<InlineSpan> spans = []; | ||
|
||
cell.asMap().forEach((index, value) { | ||
if (index > 0) { | ||
spans.add(const TextSpan(text: '\n')); | ||
} | ||
if (rowIndex == 0) { | ||
spans.add(TextSpan( | ||
text: value, | ||
style: const TextStyle( | ||
fontWeight: FontWeight.bold, color: Colors.orange))); | ||
} else if (value.isNotEmpty) { | ||
spans.add(TextSpan( | ||
text: inflection.stem, | ||
style: TextStyle( | ||
fontSize: Prefs.dictionaryFontSize.toDouble()))); | ||
spans.add(TextSpan( | ||
text: value, | ||
style: TextStyle( | ||
fontSize: Prefs.dictionaryFontSize.toDouble(), | ||
fontWeight: FontWeight.bold))); | ||
} | ||
}); | ||
|
||
return Padding( | ||
padding: const EdgeInsets.all(8.0), | ||
child: SelectableText.rich(TextSpan(children: spans)), | ||
); | ||
}) | ||
.where((cell) => cell != null) | ||
.cast<Padding>() | ||
.toList(), | ||
); | ||
}).toList(); | ||
|
||
if (!context.mounted) return; | ||
|
||
final isMobile = Mobile.isPhone(context); | ||
const insetPadding = 10.0; | ||
|
||
final content = isMobile | ||
? SizedBox( | ||
width: MediaQuery.of(context).size.width - 2 * insetPadding, | ||
child: _getInflectionWidget(rows), | ||
) | ||
: Container( | ||
constraints: const BoxConstraints( | ||
maxHeight: 400, | ||
maxWidth: 800, | ||
), | ||
child: _getInflectionWidget(rows), | ||
); | ||
|
||
showDialog( | ||
context: context, | ||
builder: (context) => AlertDialog( | ||
title: Text(superscripterUni(inflection.word)), | ||
contentPadding: isMobile ? EdgeInsets.zero : null, | ||
insetPadding: isMobile ? const EdgeInsets.all(insetPadding) : null, | ||
content: content, | ||
actions: [ | ||
TextButton( | ||
onPressed: () => Navigator.pop(context), | ||
child: Text(AppLocalizations.of(context)!.ok)), | ||
], | ||
), | ||
); | ||
} | ||
|
||
Scrollbar _getInflectionWidget(List<TableRow> rows) { | ||
final horizontal = ScrollController(); | ||
final vertical = ScrollController(); | ||
|
||
return Scrollbar( | ||
controller: vertical, | ||
thumbVisibility: true, | ||
trackVisibility: true, | ||
child: Scrollbar( | ||
controller: horizontal, | ||
thumbVisibility: true, | ||
trackVisibility: true, | ||
notificationPredicate: (notification) => notification.depth == 1, | ||
child: SingleChildScrollView( | ||
controller: vertical, | ||
child: SingleChildScrollView( | ||
controller: horizontal, | ||
scrollDirection: Axis.horizontal, | ||
child: Table( | ||
border: TableBorder.all(), | ||
defaultColumnWidth: const IntrinsicColumnWidth(), | ||
children: rows, | ||
), | ||
), | ||
), | ||
), | ||
); | ||
} |
Oops, something went wrong.