Last active
December 25, 2020 11:30
-
-
Save aldnav/d1ff2d12953351c88ca8dde0b09a3f88 to your computer and use it in GitHub Desktop.
Gamepedia The Escapists Crafting
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
CustomScrollView( | |
slivers: [ | |
SliverAppBar( | |
flexibleSpace: FlexibleSpaceBar( | |
title: Text("Escapists Craft"), | |
), | |
), | |
SliverList( | |
delegate: SliverChildBuilderDelegate( | |
(BuildContext context, int index) { | |
/// For dynamic content | |
} | |
), | |
), | |
] | |
) |
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
class _DetailPageState extends State<DetailPage> { | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: Text(name), | |
), | |
body: SingleChildScrollView( // Allow vertical overflow and scroll | |
child: Column( | |
children: [ | |
ConstrainedBox( | |
constraints: constraints, | |
child: CachedNetworkImage(imageUrl: iconUrl), | |
), | |
Row( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: [ | |
// Render the required components | |
ListView.builder( | |
itemCount: requirements.length, | |
scrollDirection: Axis.horizontal, | |
shrinkWrap: true, | |
itemBuilder: (context, index) { | |
// RequirementItem is just a styled box with image and text | |
return RequirementItem(data: item.requirements[index]); | |
} | |
), | |
] | |
), | |
Text(intelligence), | |
Text(description), | |
..., | |
Text(confiscated), | |
Text(category), | |
Text(stats), | |
], | |
), | |
), | |
} | |
} |
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
ListView.builder( | |
itemCount: items.length, | |
itemBuilder: (context, index) { | |
var data = items[index]; | |
return ListTile( | |
title: Text(data.name), | |
leading: ConstrainedBox( | |
constraints: styledBoxConstraints, | |
child: CachedNetworkImage(imageUrl: data.icon), | |
) | |
); | |
}, | |
); |
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
ListView.builder( | |
..., | |
itemBuilder: (context, index) { | |
... | |
return ListTile( | |
..., | |
onTap: () { | |
Navigator.push( | |
context, | |
MaterialPageRoute( | |
builder: (context) => DetailPage(item: data) | |
) | |
); | |
} | |
); | |
} | |
) |
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
#!/usr/bin/env python3 | |
import requests | |
from pyquery import PyQuery as pq | |
from collections import namedtuple | |
from pathlib import Path | |
import json | |
SITE_URL = "https://theescapists.gamepedia.com/Crafting" | |
BASE_URL = "https://theescapists.gamepedia.com/" | |
__item_fields__ = [ | |
"name", | |
"requirements", | |
"intelligence_1", | |
"intelligence_2", | |
"intelligence", | |
"extra_info", | |
"url", | |
"icon_url", | |
"description", | |
"defence", | |
"stats_in_2", | |
"confiscated", | |
"image_urls", | |
"category", | |
"damage_in_1", | |
] | |
Item = namedtuple( | |
"Item", | |
__item_fields__, | |
defaults=(None,) * len(__item_fields__) | |
) | |
Requirement = namedtuple( | |
'Requirement', | |
[ | |
"name", | |
"url", | |
"icon", | |
] | |
) | |
items_store_as_list = [] | |
column_name_mapping = { | |
'Item': 'name', | |
'Requirements': 'requirements', | |
'Intelligence Required in TE1': 'intelligence_1', | |
'Intelligence Required in TE2': 'intelligence_2', | |
'Intelligence': 'intelligence', | |
'Intelligence Required': 'intelligence', | |
'Extra Info': 'extra_info', | |
'Defence Given': 'defence', | |
'Stats in TE2': 'stats_in_2', | |
'Damage in TE1': 'damage_in_1', | |
} | |
def get_details(detail_url): | |
r = requests.get(detail_url) | |
page = pq(r.text) | |
page.make_links_absolute(base_url=BASE_URL) | |
description = page('#mw-content-text .mw-parser-output > p:first-of-type').text() | |
if not description.strip(): | |
description = page('#mw-content-text .mw-parser-output > p').text() | |
confiscated = page('table.infoboxtable tr').filter(lambda i: 'confiscated' in pq(this).text().lower()).eq(0).text() | |
image_urls = page('table.infoboxtable a.image img').map(lambda i: pq(this).attr('src')) | |
return { | |
'description': description, | |
'confiscated': confiscated, | |
'image_urls': image_urls, | |
} | |
def get_items_from_base_url(): | |
s = requests.Session() | |
r = s.get(url=SITE_URL) | |
page = pq(r.text) | |
page.make_links_absolute(base_url=BASE_URL) | |
tables = page('.wikitable') | |
categories = page('.mw-headline').map(lambda: pq(this).text()) | |
del categories[categories.index('The Escapists 1 DLC Prisons')] | |
for tbl_idx, _ in enumerate(tables): | |
table = tables.eq(tbl_idx) | |
column_names = table.find("th").map(lambda i, e: pq(e).text()) | |
try: | |
category = categories.pop(0) | |
except IndexError: | |
category = '' | |
rows = table.find('tr') | |
for row_idx, _ in enumerate(table.find('tr')): | |
if row_idx == 0: # HEADER | |
continue | |
row = rows.eq(row_idx) | |
data = row.find('td') | |
data_to_save = {} | |
data_to_save['category'] = category | |
for col_id, col_name in enumerate(column_names): | |
col_data = data.eq(col_id) | |
normalized_column_name = column_name_mapping.get(col_name, col_name) | |
# Save information from name | |
if normalized_column_name == 'name': | |
name = col_data.text().strip() | |
data_to_save['name'] = name | |
print(f'Saving "{name}"') | |
data_to_save['icon_url'] = col_data.find('img').attr('src') | |
data_to_save['url'] = col_data.find('a').attr('href') | |
# Save requirements | |
elif normalized_column_name == 'requirements': | |
requirements = [] | |
reqs_links = col_data.find('a') | |
idxs_of_requirements = [ | |
_id | |
for _id, el in enumerate(reqs_links.map(lambda i, e: pq(e).text())) | |
if el | |
] | |
reqs_images = reqs_links.map(lambda i, e: pq(e).find('img').attr('src')) | |
for idx in idxs_of_requirements: | |
try: | |
req_image = reqs_images.pop(0) | |
except IndexError: | |
req_image = None | |
requirements.append( | |
Requirement( | |
name=reqs_links.eq(idx).text(), | |
url=reqs_links.eq(idx).attr('href'), | |
icon=req_image, | |
)._asdict() | |
) | |
data_to_save['requirements'] = requirements | |
# Save intelligence | |
elif normalized_column_name in ('intelligence_1', 'intelligence_2', 'intelligence'): | |
data_to_save[normalized_column_name] = col_data.text() | |
# Save extra info | |
elif normalized_column_name == 'extra_info': | |
data_to_save['extra_info'] = col_data.text() | |
# Save defence | |
elif normalized_column_name == 'defence': | |
data_to_save['defence'] = col_data.text() | |
# Save stats | |
elif normalized_column_name == 'stats_in_2': | |
data_to_save['stats_in_2'] = col_data.text() | |
# Save damage | |
elif normalized_column_name == 'damage_in_1': | |
data_to_save['damage_in_1'] = col_data.text() | |
# Check for details | |
extra_details = get_details(data_to_save['url']) | |
data_to_save.update(extra_details) | |
# Save item to store | |
items_store_as_list.append(Item(**data_to_save)._asdict()) # As list | |
if __name__ == '__main__': | |
get_items_from_base_url() | |
with open(Path(__file__).parent / 'data.json', 'w+') as f: | |
f.write(json.dumps(items_store_as_list, indent=2)) |
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
final searchTextController = TextEditingController(); | |
// A simple search function | |
void searchItems() { | |
var name = searchTextController.text; | |
if (name.isNotEmpty) { | |
setState(() { | |
items = allItems | |
.where((o) => o.name.toLowerCase().contains(name.toLowerCase())) | |
.toList(); | |
}); | |
} else { | |
setState(() { | |
items = List.from(allItems); | |
}); | |
} | |
} | |
// On a state or widget we register a listener function to the controller | |
// When the controller notifies for changes, this function is invoked | |
searchTextController.addListener(searchItems); | |
TextField( | |
controller: searchTextController, | |
decoration: InputDecoration( | |
hintText: "Search", | |
prefixIcon: Icon(Icons.search), | |
), | |
) | |
// Clean up the controller when the widget is removed from the widget tree | |
@override | |
void dispose() { | |
searchTextController.dispose(); | |
super.dispose(); | |
} |
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
class _MyHomePageState extends State<MyHomePage> { | |
Map categorizeItems(items) { | |
var categories = Map(); | |
items.forEach((element) { | |
if (!categories.containsKey(element.category)) { | |
categories[element.category] = List(); | |
} | |
categories[element.category].add(element); | |
}); | |
return categories; | |
} | |
List<Widget> buildSlivers(itemsMap) { | |
List<Widget> slivers = []; | |
itemsMap.forEach((category, items) { | |
slivers.add(SliverStickyHeader( | |
header: Header(title: category), | |
sliver: SliverList( | |
delegate: SliverChildBuilderDelegate( | |
(BuildContext context, int index) { | |
return InkWell( | |
child: ItemCard(data: items[index]), | |
onTap: () { | |
Navigator.push( | |
context, | |
MaterialPageRoute( | |
builder: (context) => DetailPage( | |
item: items[index], | |
), | |
), | |
); | |
}, | |
); | |
}, | |
childCount: items.length, | |
), | |
), | |
)); | |
}); | |
return slivers; | |
} | |
// Widget build(BuildContext context) ... | |
// Build the widget with data. | |
Map categorizedItems = categorizeItems(_filteredItems); | |
var categorizedSlivers = buildSlivers(categorizedItems); | |
return Scaffold( | |
body: Container( | |
color: Colors.white, | |
child: CustomScrollView( | |
slivers: [ | |
SliverAppBar( | |
pinned: true, | |
flexibleSpace: FlexibleSpaceBar( | |
title: Text("Escapists Craft"), | |
), | |
backgroundColor: Colors.black, | |
textTheme: TextTheme( | |
headline6: TextStyle( | |
color: Colors.black, | |
fontSize: 36.0, | |
), | |
), | |
), | |
SliverAppBar( | |
floating: true, | |
snap: true, | |
flexibleSpace: FlexibleSpaceBar( | |
title: SearchBar( | |
searchTextController: searchTextController), | |
), | |
backgroundColor: Colors.white, | |
toolbarHeight: 10.0, | |
), | |
...categorizedSlivers, // list of tools with categories | |
], | |
), | |
), | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment