|  |  |  | @ -81,16 +81,6 @@ class SearchListFragment : VMBaseFragment<SearchListViewModel>(R.layout.fragment | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     /* | 
			
		
	
		
			
				
					|  |  |  |  |     private fun initDoc() { | 
			
		
	
		
			
				
					|  |  |  |  |         tocLiveData?.removeObservers(this@SearchListFragment) | 
			
		
	
		
			
				
					|  |  |  |  |         tocLiveData = App.db.bookChapterDao().observeByBook(viewModel.bookUrl) | 
			
		
	
		
			
				
					|  |  |  |  |         tocLiveData?.observe(viewLifecycleOwner, { | 
			
		
	
		
			
				
					|  |  |  |  |             adapter.setItems(it) | 
			
		
	
		
			
				
					|  |  |  |  |         }) | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  |     */ | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     private fun initCacheFileNames(book: Book) { | 
			
		
	
		
			
				
					|  |  |  |  |         launch(IO) { | 
			
		
	
		
			
				
					|  |  |  |  |             adapter.cacheFileNames.addAll(BookHelp.getChapterFiles(book)) | 
			
		
	
	
		
			
				
					|  |  |  | @ -113,14 +103,21 @@ class SearchListFragment : VMBaseFragment<SearchListViewModel>(R.layout.fragment | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     override fun startContentSearch(newText: String?) { | 
			
		
	
		
			
				
					|  |  |  |  |         if (!newText.isNullOrBlank()) { | 
			
		
	
		
			
				
					|  |  |  |  |             adapter.clearItems() | 
			
		
	
		
			
				
					|  |  |  |  |             viewModel.lastQuery = newText | 
			
		
	
		
			
				
					|  |  |  |  |             App.db.bookChapterDao().getChapterList(viewModel.bookUrl).map{ | 
			
		
	
		
			
				
					|  |  |  |  |                 launch(IO) { | 
			
		
	
		
			
				
					|  |  |  |  |                     val beginTime = System.currentTimeMillis() | 
			
		
	
		
			
				
					|  |  |  |  |                     if (isLocalBook || | 
			
		
	
		
			
				
					|  |  |  |  |                         adapter.cacheFileNames.contains(BookHelp.formatChapterName(it)) | 
			
		
	
		
			
				
					|  |  |  |  |                     if (isLocalBook | 
			
		
	
		
			
				
					|  |  |  |  |                         || adapter.cacheFileNames.contains(BookHelp.formatChapterName(it)) | 
			
		
	
		
			
				
					|  |  |  |  |                     ) { | 
			
		
	
		
			
				
					|  |  |  |  |                         val value = searchChapter(newText, it) | 
			
		
	
		
			
				
					|  |  |  |  |                         searchResultCounts += value | 
			
		
	
		
			
				
					|  |  |  |  |                         val searchResults = searchChapter(newText, it) | 
			
		
	
		
			
				
					|  |  |  |  |                         if (searchResults.size > 0 ){ | 
			
		
	
		
			
				
					|  |  |  |  |                             searchResultCounts += searchResults.size | 
			
		
	
		
			
				
					|  |  |  |  |                             withContext(Main){ | 
			
		
	
		
			
				
					|  |  |  |  |                                 adapter.addItems(searchResults) | 
			
		
	
		
			
				
					|  |  |  |  |                             } | 
			
		
	
		
			
				
					|  |  |  |  |                         } | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                     val finishedTime = System.currentTimeMillis() - beginTime | 
			
		
	
		
			
				
					|  |  |  |  |                     Log.d("Jason", "Search finished, the total time cost is $finishedTime") | 
			
		
	
	
		
			
				
					|  |  |  | @ -131,15 +128,17 @@ class SearchListFragment : VMBaseFragment<SearchListViewModel>(R.layout.fragment | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     private suspend fun searchChapter(query: String, chapter: BookChapter?): Int  { | 
			
		
	
		
			
				
					|  |  |  |  |     private fun searchChapter(query: String, chapter: BookChapter?): MutableList<SearchResult>  { | 
			
		
	
		
			
				
					|  |  |  |  |         val startTime = System.currentTimeMillis() | 
			
		
	
		
			
				
					|  |  |  |  |         val searchResult: MutableList<SearchResult> = mutableListOf() | 
			
		
	
		
			
				
					|  |  |  |  |         val searchResults: MutableList<SearchResult> = mutableListOf() | 
			
		
	
		
			
				
					|  |  |  |  |         var positions : List<Int>? = listOf() | 
			
		
	
		
			
				
					|  |  |  |  |         if (chapter != null){ | 
			
		
	
		
			
				
					|  |  |  |  |             Log.d("Jason", "Search ${chapter.title}") | 
			
		
	
		
			
				
					|  |  |  |  |             viewModel.book?.let { bookSource -> | 
			
		
	
		
			
				
					|  |  |  |  |                 val bookContent = BookHelp.getContent(bookSource, chapter) | 
			
		
	
		
			
				
					|  |  |  |  |                 if (bookContent != null){ | 
			
		
	
		
			
				
					|  |  |  |  |                     //todo: 搜索替换后的正文 | 
			
		
	
		
			
				
					|  |  |  |  |                     //todo: 计算搜索结果所在的pageIndex直接跳转 | 
			
		
	
		
			
				
					|  |  |  |  |                 /* replace content, let's focus on original content first | 
			
		
	
		
			
				
					|  |  |  |  |                 chapter.title = when (AppConfig.chineseConverterType) { | 
			
		
	
		
			
				
					|  |  |  |  |                     1 -> HanLP.convertToSimplifiedChinese(chapter.title) | 
			
		
	
	
		
			
				
					|  |  |  | @ -168,30 +167,28 @@ class SearchListFragment : VMBaseFragment<SearchListViewModel>(R.layout.fragment | 
			
		
	
		
			
				
					|  |  |  |  |                 */ | 
			
		
	
		
			
				
					|  |  |  |  |                     positions = countMatches(bookContent, query) | 
			
		
	
		
			
				
					|  |  |  |  |                     positions?.map{ | 
			
		
	
		
			
				
					|  |  |  |  |                         searchResult.add( | 
			
		
	
		
			
				
					|  |  |  |  |                             SearchResult(index = 0, | 
			
		
	
		
			
				
					|  |  |  |  |                                 text = constructText(bookContent, it), | 
			
		
	
		
			
				
					|  |  |  |  |                                 chapterTitle = chapter.title, | 
			
		
	
		
			
				
					|  |  |  |  |                                 query = query, | 
			
		
	
		
			
				
					|  |  |  |  |                                 pageSize = 0, // to be finished | 
			
		
	
		
			
				
					|  |  |  |  |                                 chapterIndex = chapter.index,   // to be finished | 
			
		
	
		
			
				
					|  |  |  |  |                                 pageIndex = 0,  // to be finished | 
			
		
	
		
			
				
					|  |  |  |  |                                 ) | 
			
		
	
		
			
				
					|  |  |  |  |                         val result = SearchResult(index = 0, | 
			
		
	
		
			
				
					|  |  |  |  |                             text = constructText(bookContent, it), | 
			
		
	
		
			
				
					|  |  |  |  |                             chapterTitle = chapter.title, | 
			
		
	
		
			
				
					|  |  |  |  |                             query = query, | 
			
		
	
		
			
				
					|  |  |  |  |                             pageSize = 0, // to be finished | 
			
		
	
		
			
				
					|  |  |  |  |                             chapterIndex = chapter.index,   // to be finished | 
			
		
	
		
			
				
					|  |  |  |  |                             pageIndex = 0,  // to be finished | 
			
		
	
		
			
				
					|  |  |  |  |                         ) | 
			
		
	
		
			
				
					|  |  |  |  |                         searchResults.add(result) | 
			
		
	
		
			
				
					|  |  |  |  |                         Log.d("Jason", result.presentText) | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                     adapter.addItems(searchResult) | 
			
		
	
		
			
				
					|  |  |  |  |                     Log.d("Jason", "Search ${chapter.title} finished, the appeared count is ${positions!!.size}") | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |             val endTime = System.currentTimeMillis() - startTime | 
			
		
	
		
			
				
					|  |  |  |  |             Log.d("Jason", "Search ${chapter.title} finished, the time cost is $endTime") | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         return positions!!.size | 
			
		
	
		
			
				
					|  |  |  |  |         return searchResults | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     private fun countMatches(content: String, pattern: String): List<Int> { | 
			
		
	
		
			
				
					|  |  |  |  |         val position : MutableList<Int> = mutableListOf() | 
			
		
	
		
			
				
					|  |  |  |  |         var count = 0 | 
			
		
	
		
			
				
					|  |  |  |  |         var index = content.indexOf(pattern) | 
			
		
	
		
			
				
					|  |  |  |  |         while(index >= 0){ | 
			
		
	
		
			
				
					|  |  |  |  |             position.add(index) | 
			
		
	
	
		
			
				
					|  |  |  | @ -201,8 +198,11 @@ class SearchListFragment : VMBaseFragment<SearchListViewModel>(R.layout.fragment | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     private fun constructText(content: String, position: Int): String{ | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         val length = 10 | 
			
		
	
		
			
				
					|  |  |  |  |         // 构建关键词周边文字,在搜索结果里显示 | 
			
		
	
		
			
				
					|  |  |  |  |         // todo: 判断段落,只在关键词所在段落内分割 | 
			
		
	
		
			
				
					|  |  |  |  |         // todo: 利用标点符号分割完整的句 | 
			
		
	
		
			
				
					|  |  |  |  |         // todo: length和设置结合,自由调整周边文字长度 | 
			
		
	
		
			
				
					|  |  |  |  |         val length = 20 | 
			
		
	
		
			
				
					|  |  |  |  |         var po1 = position - length | 
			
		
	
		
			
				
					|  |  |  |  |         var po2 = position + length | 
			
		
	
		
			
				
					|  |  |  |  |         if (po1 <0) { | 
			
		
	
	
		
			
				
					|  |  |  | @ -211,18 +211,7 @@ class SearchListFragment : VMBaseFragment<SearchListViewModel>(R.layout.fragment | 
			
		
	
		
			
				
					|  |  |  |  |         if (po2 > content.length){ | 
			
		
	
		
			
				
					|  |  |  |  |             po2 = content.length | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         return content.substring(po1, po2) | 
			
		
	
		
			
				
					|  |  |  |  |         /* | 
			
		
	
		
			
				
					|  |  |  |  |         if (position >= length && position <= content.length - length){ | 
			
		
	
		
			
				
					|  |  |  |  |             return content.substring(position - length, position + length) | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         else if (position <= length){ | 
			
		
	
		
			
				
					|  |  |  |  |             return content.substring(0, position + length) | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         else if (position >= content.length - length){ | 
			
		
	
		
			
				
					|  |  |  |  |             return content.substring(position - length, content.length) | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |          */ | 
			
		
	
		
			
				
					|  |  |  |  |         return "..." + content.substring(po1, po2) | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     val isLocalBook: Boolean | 
			
		
	
	
		
			
				
					|  |  |  | 
 |