Skip to content

Commit

Permalink
Add a basic draft for CSE promotion.
Browse files Browse the repository at this point in the history
First attemp for #6
  • Loading branch information
guojiex committed Mar 11, 2019
1 parent 13dda54 commit 5ee34ec
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 16 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ samples, guidance on mobile development, and a full API reference.

### watch demo on youtube.

[![demo_on_youtube](https://img.youtube.com/vi/dXPWOY69XuI/hqdefault.jpg)](https://youtu.be/dXPWOY69XuI)
[![demo_on_youtube](https://img.youtube.com/vi/IW1yq-cZSxg/hqdefault.jpg)](https://youtu.be/IW1yq-cZSxg)
1 change: 1 addition & 0 deletions lib/custom_search_search_delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ class CustomSearchInfiniteSearchDelegate extends CustomSearchSearchDelegate {
return ImageSearchResultPage(
dataSource, snapshot.data, searchQuery);
case SearchType.web:
print('here');
return WebSearchResultPage(
dataSource, snapshot.data, searchQuery);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ class SearchDemoApp extends StatelessWidget {
'/websearch': (context) => webSearchDemo,
'/imagesearch': (context) =>
CustomSearchDemoPage(CustomSearchDemoType.imageSearch),

'/promotionwebsearch': (context) =>
CustomSearchDemoPage(CustomSearchDemoType.promotionWebSearch),
},
title: 'Custom Search Engine Flutter Demo');
}
Expand Down
66 changes: 58 additions & 8 deletions lib/search_data_source.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,54 @@ class SearchResult {
: result.image.contextLink.hashCode;
}

class PromotionImage {
int height;
String source;
int width;

PromotionImage(customsearch.PromotionImage promotionImage) {
this.height = promotionImage.height;
this.width = promotionImage.width;
this.source = promotionImage.source;
}
}

class PromotionBodyLines {
String htmlTitle;
String link;
String title;
String url;

PromotionBodyLines(customsearch.PromotionBodyLines bodyLines) {
this.htmlTitle = bodyLines.htmlTitle;
this.link = bodyLines.link;
this.title = bodyLines.title;
this.url = bodyLines.url;
}
}

class Promotion {
final customsearch.Promotion promotion;
String title;
String link;
String displayLink;
PromotionImage promotionImage;
List<PromotionBodyLines> promotionBodyLines = new List<PromotionBodyLines>();

Promotion(customsearch.Promotion promotion) {
print('here');
this.title = promotion.title;
this.link = promotion.link;
this.displayLink = promotion.displayLink;
this.promotionImage = PromotionImage(promotion.image);
promotion.bodyLines.forEach((bodyLines) =>
this.promotionBodyLines.add(PromotionBodyLines(bodyLines)));
print(this);
}

Promotion(this.promotion);
@override
String toString() {
return 'Promotion{title: $title, link: $link, displayLink: $displayLink, promotionImage: $promotionImage, promotionBodyLines: $promotionBodyLines}';
}
}

class Refinement {
Expand Down Expand Up @@ -85,18 +129,25 @@ class SearchResults {
var results = new List<SearchResult>();
search.items.forEach(
(item) => results.add(SearchResult.escapeLineBreakInSnippet(item)));

// Deduplicate search result.
this.searchResults = Set<SearchResult>.from(results).toList();
search.context.facets.forEach((listOfFacet) {
this.refinements.add(Refinement(listOfFacet[0]));
});
print(search.context.facets);
if (search.context.facets != null) {
search.context.facets.forEach((listOfFacet) {
this.refinements.add(Refinement(listOfFacet[0]));
});
}
if (search.promotions != null) {
search.promotions
.forEach((promotion) => this.promotions.add(Promotion(promotion)));
}
}

@override
String toString() {
return 'SearchResults{searchResults: $searchResults, refinements: $refinements, nextPage: $nextPage}';
}

}

/// A wrapper class for search request, to make caching search request possible.
Expand Down Expand Up @@ -450,7 +501,7 @@ class CustomSearchDataSource implements SearchDataSource {
ExpireCache<SearchQuery, SearchResults>();

CustomSearchDataSource({@required this.cx, @required this.apiKey})
:assert(apiKey.isNotEmpty) {
: assert(apiKey.isNotEmpty) {
var client = auth.clientViaApiKey(apiKey);
this.api = new customsearch.CustomsearchApi(client);
}
Expand All @@ -469,7 +520,6 @@ class CustomSearchDataSource implements SearchDataSource {
} else {
return await _cache.get(searchQuery);
}

final result = await searchQuery.runSearch(this.api);
_cache.set(searchQuery, result);
print('call search backend');
Expand Down
23 changes: 21 additions & 2 deletions lib/ui/custom_search_demo_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ enum CustomSearchDemoType {

/// Search for image.
imageSearch,
promotionWebSearch,
}

class CustomSearchDemoPage extends StatefulWidget {
Expand All @@ -34,6 +35,8 @@ class CustomSearchDemoPage extends StatefulWidget {
return _CustomSearchDemoPageState.customWebSearch();
case CustomSearchDemoType.imageSearch:
return _CustomSearchDemoPageState.customImageSearch();
case CustomSearchDemoType.promotionWebSearch:
return _CustomSearchDemoPageState.customPromotionWebSearch();
default:
return null;
}
Expand Down Expand Up @@ -73,7 +76,9 @@ class _CustomSearchDemoPageState extends State<CustomSearchDemoPage> {
apiKey: ''));
this.hintText = 'Google Custom Image Search';
otherRoutes = [
Tuple2<String, String>('Custom Web Search Demo', '/websearch')
Tuple2<String, String>('Custom Web Search Demo', '/websearch'),
Tuple2<String, String>(
'Custom Web Search Promotion Demo', '/promotionwebsearch')
];
}

Expand All @@ -85,10 +90,24 @@ class _CustomSearchDemoPageState extends State<CustomSearchDemoPage> {
apiKey: ''));
this.hintText = 'Google Custom Web Search';
otherRoutes = [
Tuple2<String, String>('Custom Image Search Demo', '/imagesearch')
Tuple2<String, String>('Custom Image Search Demo', '/imagesearch'),
Tuple2<String, String>(
'Custom Web Search Promotion Demo', '/promotionwebsearch')
];
}

_CustomSearchDemoPageState.customPromotionWebSearch() {
// flutter with promotion
this.delegate = new CustomSearchInfiniteSearchDelegate(
dataSource: CustomSearchDataSource(
cx: '013098254965507895640:ebp1trsjo0a',
apiKey: ''));
this.hintText = 'Google Custom Web Search with Promotion';
otherRoutes = [
Tuple2<String, String>('Custom Web Search Demo', '/websearch'),
Tuple2<String, String>('Custom Image Search Demo', '/imagesearch')
];
}

final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();

Expand Down
79 changes: 79 additions & 0 deletions lib/ui/promotion_card.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import 'package:flutter/material.dart';
import 'package:flutter_app_cse/search_data_source.dart';
import 'package:url_launcher/url_launcher.dart';

class PromotionCard extends StatelessWidget {
const PromotionCard({@required this.promotion});

final Promotion promotion;

Widget _generateTitleTile(BuildContext context) {
final ThemeData theme = Theme.of(context);
return ListTile(
title: Text(
'[promotion] ' + this.promotion.title,
style: theme.textTheme.headline.copyWith(
fontSize: 15.0, fontWeight: FontWeight.bold, color: Colors.blue),
),
subtitle: new Text(
this.promotion.displayLink,
style:
theme.textTheme.body1.copyWith(fontSize: 14.0, color: Colors.green),
),
);
}

Widget _generateBodyTile(BuildContext context) {
final ThemeData theme = Theme.of(context);
return Container(
padding: const EdgeInsets.only(
left: 8.0,
bottom: 8.0,
),
child: new Row(children: [
// TODO: wait until CSE fix their API.
// Expanded(
// flex: 1,
// child:
// Image.network('https:' + this.promotion.promotionImage.source)),
Expanded(
// flex: 4,
child: Container(
padding: const EdgeInsets.only(left: 4.0, right: 8.0),
child: Text(
'[promotion] ' + this.promotion.promotionBodyLines[0].title,
style: theme.textTheme.body1,
textAlign: TextAlign.left,
))),
]),
);
}

@override
Widget build(BuildContext context) {
return new GestureDetector(
onTap: () async {
if (await canLaunch(this.promotion.link)) {
await launch(this.promotion.link);
}
},
child: Container(
decoration: new BoxDecoration(boxShadow: [
new BoxShadow(
color: Colors.grey,
blurRadius: 1.0,
),
]),
child: new Card(
color: Colors.lightGreen[50],
child: Column(
children: [
_generateTitleTile(context),
new Divider(color: Colors.black26),
_generateBodyTile(context),
],
),
),
));
}
}
15 changes: 11 additions & 4 deletions lib/ui/web_search_result_page.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import 'package:flutter/material.dart';

import '../search_data_source.dart';
import '../shared_constant.dart';
import 'no_result_card.dart';
import 'web_search_result_card.dart';
import 'promotion_card.dart';

@immutable
class WebSearchResultPage extends StatefulWidget {
Expand Down Expand Up @@ -51,9 +51,16 @@ class _WebSearchResultPageState extends State<WebSearchResultPage>
return ListView(
shrinkWrap: true,
primary: false,
children: searchResults.searchResults.map((searchResult) {
return WebSearchResultCard(searchResult: searchResult);
}).toList());
children: _buildWebResultWidgetList(searchResults));
}

List<Widget> _buildWebResultWidgetList(SearchResults searchResults) {
List<Widget> _results = new List<Widget>();
_results.addAll(searchResults.promotions
.map((promotion) => PromotionCard(promotion: promotion)));
_results.addAll(searchResults.searchResults.map(
(searchResult) => WebSearchResultCard(searchResult: searchResult)));
return _results;
}

Widget _buildWebListPage(BuildContext context) {
Expand Down

0 comments on commit 5ee34ec

Please sign in to comment.