Skip to content

Instantly share code, notes, and snippets.

@aldnav
Last active December 25, 2020 11:30
Show Gist options
  • Save aldnav/d1ff2d12953351c88ca8dde0b09a3f88 to your computer and use it in GitHub Desktop.
Save aldnav/d1ff2d12953351c88ca8dde0b09a3f88 to your computer and use it in GitHub Desktop.
Gamepedia The Escapists Crafting
CustomScrollView(
slivers: [
SliverAppBar(
flexibleSpace: FlexibleSpaceBar(
title: Text("Escapists Craft"),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
/// For dynamic content
}
),
),
]
)
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),
],
),
),
}
}
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),
)
);
},
);
ListView.builder(
...,
itemBuilder: (context, index) {
...
return ListTile(
...,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailPage(item: data)
)
);
}
);
}
)
#!/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))
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();
}
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