11import 'dart:convert' ;
22
3+ import 'package:flutter/cupertino.dart' ;
34import 'package:flutter/material.dart' ;
45import 'package:flutter_inappwebview/flutter_inappwebview.dart' ;
56import 'package:just_audio/just_audio.dart' ;
67import 'package:nhk_easy/error_reporter.dart' ;
78import 'package:nhk_easy/model/news.dart' ;
9+ import 'package:nhk_easy/model/word.dart' ;
10+ import 'package:nhk_easy/service/word_service.dart' ;
811
912class NewsDetail extends StatefulWidget {
1013 final News news;
@@ -19,7 +22,10 @@ class NewsDetailState extends State<NewsDetail> {
1922 News _news;
2023 bool _isPlaying = false ;
2124 AudioPlayer _audioPlayer;
22- InAppWebViewController _inAppWebViewController;
25+ bool _showDictionary = false ;
26+ Word _currentWord = null ;
27+ List <Word > _words = [];
28+ WordService _wordService = WordService ();
2329
2430 @override
2531 void initState () {
@@ -33,6 +39,13 @@ class NewsDetailState extends State<NewsDetail> {
3339 ErrorReporter .reportError (error, stackTrace);
3440 });
3541 }
42+
43+ _wordService
44+ .fetchWordList (this ._news.newsId)
45+ .then ((words) => this ._words = words)
46+ .catchError ((error, stackTrace) {
47+ ErrorReporter .reportError (error, stackTrace);
48+ });
3649 }
3750
3851 @override
@@ -55,34 +68,76 @@ class NewsDetailState extends State<NewsDetail> {
5568 ),
5669 body: Padding (
5770 padding: EdgeInsets .all (16.0 ),
58- child: InAppWebView (
59- initialUrl: Uri .dataFromString (_buildHtml (_news),
60- mimeType: 'text/html' , encoding: utf8)
61- .toString (),
62- onWebViewCreated: (InAppWebViewController inAppWebViewController) {
63- setState (() {
64- this ._inAppWebViewController = inAppWebViewController;
65- });
66-
67- inAppWebViewController.addJavaScriptHandler (
68- handlerName: 'lookup' ,
69- callback: (args) {
70- print (args);
71- });
72- },
73- onLoadStop:
74- (InAppWebViewController inAppWebViewController, String url) {
75- inAppWebViewController.injectJavascriptFileFromAsset (
76- assetFilePath: 'assets/js/news-detail.js' );
77- },
78- onConsoleMessage: (InAppWebViewController inAppWebViewController,
79- ConsoleMessage consoleMessage) {
80- print (consoleMessage.message);
81-
82- if (consoleMessage.messageLevel == ConsoleMessageLevel .ERROR ) {
83- ErrorReporter .reportError (consoleMessage.message, null );
84- }
85- },
71+ child: Stack (
72+ children: < Widget > [
73+ InAppWebView (
74+ initialUrl: Uri .dataFromString (_buildHtml (_news),
75+ mimeType: 'text/html' , encoding: utf8)
76+ .toString (),
77+ onWebViewCreated:
78+ (InAppWebViewController inAppWebViewController) {
79+ inAppWebViewController.addJavaScriptHandler (
80+ handlerName: 'lookup' ,
81+ callback: (args) {
82+ String wordId = args.length > 0 ? args[0 ] : null ;
83+ Word word = _words.firstWhere (
84+ (word) => 'id-${word .idInNews }' == wordId);
85+
86+ if (word != null ) {
87+ setState (() {
88+ _currentWord = word;
89+ _showDictionary = true ;
90+ });
91+ }
92+ });
93+ },
94+ onLoadStop: (InAppWebViewController inAppWebViewController,
95+ String url) {
96+ inAppWebViewController.injectJavascriptFileFromAsset (
97+ assetFilePath: 'assets/js/news-detail.js' );
98+ },
99+ onConsoleMessage:
100+ (InAppWebViewController inAppWebViewController,
101+ ConsoleMessage consoleMessage) {
102+ print (consoleMessage.message);
103+
104+ if (consoleMessage.messageLevel ==
105+ ConsoleMessageLevel .ERROR ) {
106+ ErrorReporter .reportError (consoleMessage.message, null );
107+ }
108+ },
109+ ),
110+ Container (
111+ child: _showDictionary
112+ ? Center (
113+ child: Card (
114+ child: Container (
115+ padding: EdgeInsets .all (16 ),
116+ child: Column (
117+ crossAxisAlignment: CrossAxisAlignment .start,
118+ mainAxisSize: MainAxisSize .min,
119+ children: < Widget > [
120+ _buildWordDefinitions (_currentWord),
121+ ButtonBar (
122+ children: < Widget > [
123+ FlatButton (
124+ child: const Text ('Close' ),
125+ onPressed: () {
126+ setState (() {
127+ _currentWord = null ;
128+ _showDictionary = false ;
129+ });
130+ },
131+ ),
132+ ],
133+ ),
134+ ],
135+ ),
136+ )),
137+ )
138+ : Container (),
139+ )
140+ ],
86141 ),
87142 ),
88143 floatingActionButton: _hasAudio ()
@@ -147,4 +202,31 @@ class NewsDetailState extends State<NewsDetail> {
147202 bool _hasAudio () {
148203 return _news.m3u8Url != null && _news.m3u8Url != '' ;
149204 }
205+
206+ Widget _buildWordDefinitions (Word word) {
207+ if (word == null ) {
208+ return Container ();
209+ }
210+
211+ final definitions = word.definitions
212+ .asMap ()
213+ .entries
214+ .map ((entry) => Text (
215+ '${entry .key + 1 }. ${entry .value .definition }' ,
216+ style: TextStyle (fontSize: 16 ),
217+ ))
218+ .toList ();
219+
220+ List <Widget > columns = [];
221+ columns.add (Text (
222+ word.name,
223+ style: TextStyle (fontSize: 18 ),
224+ ));
225+ columns.addAll (definitions);
226+
227+ return Column (
228+ crossAxisAlignment: CrossAxisAlignment .start,
229+ children: columns,
230+ );
231+ }
150232}
0 commit comments