mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 13:58:47 +00:00
Add deeplink store sample (#1698)
* Adds deeplink store app * push * update md * update
This commit is contained in:
43
deeplink_store_example/lib/main.dart
Normal file
43
deeplink_store_example/lib/main.dart
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import 'product_category_list.dart';
|
||||
import 'product_list.dart';
|
||||
import 'product_details.dart';
|
||||
|
||||
void main() => runApp(const MyApp());
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp.router(
|
||||
debugShowCheckedModeBanner: false,
|
||||
routerConfig: GoRouter(
|
||||
routes: [
|
||||
GoRoute(path: '/', builder: (_, __) => const ProductList(),
|
||||
routes: [
|
||||
GoRoute(path: ':id', builder: (_, __) => const ProductDetails()),
|
||||
],
|
||||
),
|
||||
GoRoute(path: '/category/:category', builder: (_, __) => const ProductCategoryList()),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
299
deeplink_store_example/lib/model/products_repository.dart
Normal file
299
deeplink_store_example/lib/model/products_repository.dart
Normal file
@@ -0,0 +1,299 @@
|
||||
// Copyright 2018-present the Flutter authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
enum Category {
|
||||
all,
|
||||
accessories,
|
||||
clothing,
|
||||
home,
|
||||
}
|
||||
|
||||
class ProductsRepository {
|
||||
static const _allProducts = <Product>[
|
||||
Product(
|
||||
category: Category.accessories,
|
||||
id: 0,
|
||||
name: 'Vagabond sack',
|
||||
price: 120,
|
||||
),
|
||||
Product(
|
||||
category: Category.accessories,
|
||||
id: 1,
|
||||
name: 'Stella sunglasses',
|
||||
price: 58,
|
||||
),
|
||||
Product(
|
||||
category: Category.accessories,
|
||||
id: 2,
|
||||
name: 'Whitney belt',
|
||||
price: 35,
|
||||
),
|
||||
Product(
|
||||
category: Category.accessories,
|
||||
id: 3,
|
||||
name: 'Garden strand',
|
||||
price: 98,
|
||||
),
|
||||
Product(
|
||||
category: Category.accessories,
|
||||
id: 4,
|
||||
name: 'Strut earrings',
|
||||
price: 34,
|
||||
),
|
||||
Product(
|
||||
category: Category.accessories,
|
||||
id: 5,
|
||||
name: 'Varsity socks',
|
||||
price: 12,
|
||||
),
|
||||
Product(
|
||||
category: Category.accessories,
|
||||
id: 6,
|
||||
name: 'Weave keyring',
|
||||
price: 16,
|
||||
),
|
||||
Product(
|
||||
category: Category.accessories,
|
||||
id: 7,
|
||||
name: 'Gatsby hat',
|
||||
price: 40,
|
||||
),
|
||||
Product(
|
||||
category: Category.accessories,
|
||||
id: 8,
|
||||
name: 'Shrug bag',
|
||||
price: 198,
|
||||
),
|
||||
Product(
|
||||
category: Category.home,
|
||||
id: 9,
|
||||
name: 'Gilt desk trio',
|
||||
price: 58,
|
||||
),
|
||||
Product(
|
||||
category: Category.home,
|
||||
id: 10,
|
||||
name: 'Copper wire rack',
|
||||
price: 18,
|
||||
),
|
||||
Product(
|
||||
category: Category.home,
|
||||
id: 11,
|
||||
name: 'Soothe ceramic set',
|
||||
price: 28,
|
||||
),
|
||||
Product(
|
||||
category: Category.home,
|
||||
id: 12,
|
||||
name: 'Hurrahs tea set',
|
||||
price: 34,
|
||||
),
|
||||
Product(
|
||||
category: Category.home,
|
||||
id: 13,
|
||||
name: 'Blue stone mug',
|
||||
price: 18,
|
||||
),
|
||||
Product(
|
||||
category: Category.home,
|
||||
id: 14,
|
||||
name: 'Rainwater tray',
|
||||
price: 27,
|
||||
),
|
||||
Product(
|
||||
category: Category.home,
|
||||
id: 15,
|
||||
name: 'Chambray napkins',
|
||||
price: 16,
|
||||
),
|
||||
Product(
|
||||
category: Category.home,
|
||||
id: 16,
|
||||
name: 'Succulent planters',
|
||||
price: 16,
|
||||
),
|
||||
Product(
|
||||
category: Category.home,
|
||||
id: 17,
|
||||
name: 'Quartet table',
|
||||
price: 175,
|
||||
),
|
||||
Product(
|
||||
category: Category.home,
|
||||
id: 18,
|
||||
name: 'Kitchen quattro',
|
||||
price: 129,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 19,
|
||||
name: 'Clay sweater',
|
||||
price: 48,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 20,
|
||||
name: 'Sea tunic',
|
||||
price: 45,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 21,
|
||||
name: 'Plaster tunic',
|
||||
price: 38,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 22,
|
||||
name: 'White pinstripe shirt',
|
||||
price: 70,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 23,
|
||||
name: 'Chambray shirt',
|
||||
price: 70,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 24,
|
||||
name: 'Seabreeze sweater',
|
||||
price: 60,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 25,
|
||||
name: 'Gentry jacket',
|
||||
price: 178,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 26,
|
||||
name: 'Navy trousers',
|
||||
price: 74,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 27,
|
||||
name: 'Walter henley (white)',
|
||||
price: 38,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 28,
|
||||
name: 'Surf and perf shirt',
|
||||
price: 48,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 29,
|
||||
name: 'Ginger scarf',
|
||||
price: 98,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 30,
|
||||
name: 'Ramona crossover',
|
||||
price: 68,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 31,
|
||||
name: 'Chambray shirt',
|
||||
price: 38,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 32,
|
||||
name: 'Classic white collar',
|
||||
price: 58,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 33,
|
||||
name: 'Cerise scallop tee',
|
||||
price: 42,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 34,
|
||||
name: 'Shoulder rolls tee',
|
||||
price: 27,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 35,
|
||||
name: 'Grey slouch tank',
|
||||
price: 24,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 36,
|
||||
name: 'Sunshirt dress',
|
||||
price: 58,
|
||||
),
|
||||
Product(
|
||||
category: Category.clothing,
|
||||
id: 37,
|
||||
name: 'Fine lines tee',
|
||||
price: 58,
|
||||
),
|
||||
];
|
||||
|
||||
static List<Product> loadProducts({Category category = Category.all}) {
|
||||
if (category == Category.all) {
|
||||
return _allProducts;
|
||||
} else {
|
||||
return _allProducts.where((p) => p.category == category).toList();
|
||||
}
|
||||
}
|
||||
|
||||
static Product loadProduct({required int id}) {
|
||||
return _allProducts.firstWhere((Product p) => p.id == id);
|
||||
}
|
||||
}
|
||||
|
||||
String getCategoryTitle(Category category) {
|
||||
switch(category) {
|
||||
case Category.all:
|
||||
return 'All';
|
||||
case Category.accessories:
|
||||
return 'Accessories';
|
||||
case Category.clothing:
|
||||
return 'Clothing';
|
||||
case Category.home:
|
||||
return 'Home Decorations';
|
||||
}
|
||||
}
|
||||
|
||||
class Product {
|
||||
const Product({
|
||||
required this.category,
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.price,
|
||||
});
|
||||
|
||||
final Category category;
|
||||
final int id;
|
||||
final String name;
|
||||
final int price;
|
||||
|
||||
String get assetName => '$id-0.jpg';
|
||||
String get assetName2X => '2.0x/$id-0.jpg';
|
||||
String get assetPackage => 'shrine_images';
|
||||
|
||||
@override
|
||||
String toString() => '$name (id=$id)';
|
||||
}
|
||||
51
deeplink_store_example/lib/product_category_list.dart
Normal file
51
deeplink_store_example/lib/product_category_list.dart
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import 'model/products_repository.dart';
|
||||
import 'row_item.dart';
|
||||
import 'styles.dart';
|
||||
|
||||
class ProductCategoryList extends StatelessWidget {
|
||||
const ProductCategoryList({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final GoRouterState state = GoRouterState.of(context);
|
||||
final Category category = Category.values.firstWhere(
|
||||
(Category value) => value.toString().contains(state.params['category']!),
|
||||
orElse: () => Category.all,
|
||||
);
|
||||
final List<Widget> children = ProductsRepository.loadProducts(category: category)
|
||||
.map<Widget>((Product p) => RowItem(product: p))
|
||||
.toList();
|
||||
return Scaffold(
|
||||
backgroundColor: Styles.scaffoldBackground,
|
||||
body: CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
SliverAppBar(
|
||||
title: Text(getCategoryTitle(category), style: Styles.productListTitle),
|
||||
backgroundColor: Styles.scaffoldAppBarBackground,
|
||||
pinned: true,
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildListDelegate(children),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
66
deeplink_store_example/lib/product_details.dart
Normal file
66
deeplink_store_example/lib/product_details.dart
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import 'model/products_repository.dart';
|
||||
import 'styles.dart';
|
||||
|
||||
class ProductDetails extends StatelessWidget {
|
||||
const ProductDetails({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final String currentId = GoRouterState.of(context).params['id']!;
|
||||
final Product product = ProductsRepository.loadProduct(id: int.parse(currentId));
|
||||
return Scaffold(
|
||||
body: ListView(
|
||||
children: <Widget>[
|
||||
ProductPicture(product: product),
|
||||
Styles.spacer,
|
||||
Text(product.name, style: Styles.productPageItemName),
|
||||
Styles.spacer,
|
||||
Text('\$${product.price}', style: Styles.productPageItemPrice),
|
||||
Styles.largeSpacer,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ProductPicture extends StatelessWidget{
|
||||
const ProductPicture({super.key, required this.product});
|
||||
|
||||
final Product product;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
return Image.asset(
|
||||
product.assetName2X,
|
||||
package: product.assetPackage,
|
||||
fit: BoxFit.cover,
|
||||
width: constraints.maxWidth,
|
||||
);
|
||||
},
|
||||
),
|
||||
const BackButton(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
45
deeplink_store_example/lib/product_list.dart
Normal file
45
deeplink_store_example/lib/product_list.dart
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'model/products_repository.dart';
|
||||
import 'row_item.dart';
|
||||
import 'styles.dart';
|
||||
|
||||
class ProductList extends StatelessWidget {
|
||||
const ProductList({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> children = ProductsRepository.loadProducts()
|
||||
.map<Widget>((Product p) => RowItem(product: p))
|
||||
.toList();
|
||||
return Scaffold(
|
||||
backgroundColor: Styles.scaffoldBackground,
|
||||
body: CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
const SliverAppBar(
|
||||
title: Text('Material Store', style: Styles.productListTitle),
|
||||
backgroundColor: Styles.scaffoldAppBarBackground,
|
||||
pinned: true,
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildListDelegate(children),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
56
deeplink_store_example/lib/row_item.dart
Normal file
56
deeplink_store_example/lib/row_item.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import 'model/products_repository.dart';
|
||||
import 'styles.dart';
|
||||
|
||||
class RowItem extends StatelessWidget {
|
||||
const RowItem({
|
||||
required this.product,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final Product product;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
shape: const Border.symmetric(
|
||||
horizontal: BorderSide(color: Styles.productRowDivider),
|
||||
),
|
||||
leading: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: Image.asset(
|
||||
product.assetName,
|
||||
package: product.assetPackage,
|
||||
fit: BoxFit.cover,
|
||||
width: 68,
|
||||
height: 68,
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
product.name,
|
||||
style: Styles.productRowItemName,
|
||||
),
|
||||
subtitle: Text(
|
||||
'\$${product.price}',
|
||||
style: Styles.productRowItemPrice,
|
||||
),
|
||||
onTap: () => context.push('/${product.id}'),
|
||||
);
|
||||
}
|
||||
}
|
||||
46
deeplink_store_example/lib/styles.dart
Normal file
46
deeplink_store_example/lib/styles.dart
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2018 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
abstract class Styles {
|
||||
static const TextStyle productListTitle = TextStyle(
|
||||
color: Color.fromRGBO(0, 0, 0, 0.8),
|
||||
);
|
||||
static const TextStyle productRowItemName = TextStyle(
|
||||
color: Color.fromRGBO(0, 0, 0, 0.8),
|
||||
fontSize: 18,
|
||||
fontStyle: FontStyle.normal,
|
||||
fontWeight: FontWeight.normal,
|
||||
);
|
||||
|
||||
static const TextStyle productRowItemPrice = TextStyle(
|
||||
color: Color(0xFF8E8E93),
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w300,
|
||||
);
|
||||
|
||||
static const TextStyle productPageItemName = TextStyle(
|
||||
color: Color.fromRGBO(0, 0, 0, 0.8),
|
||||
fontSize: 20,
|
||||
fontStyle: FontStyle.normal,
|
||||
fontWeight: FontWeight.bold,
|
||||
);
|
||||
|
||||
static const TextStyle productPageItemPrice = TextStyle(
|
||||
color: Color.fromRGBO(0, 0, 0, 0.8),
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
);
|
||||
|
||||
static const Color productRowDivider = Color(0xFFD9D9D9);
|
||||
|
||||
static const Color scaffoldBackground = Color(0xfff0f0f0);
|
||||
|
||||
static const Color scaffoldAppBarBackground = Color(0xffffffff);
|
||||
|
||||
static const Widget spacer = SizedBox(height: 10);
|
||||
|
||||
static const Widget largeSpacer = SizedBox(height: 100);
|
||||
}
|
||||
Reference in New Issue
Block a user