1
0
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:
chunhtai
2023-03-16 09:12:32 -07:00
committed by GitHub
parent db18c98799
commit 481c2e3d1d
134 changed files with 5281 additions and 0 deletions

View 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()),
],
),
);
}
}

View 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)';
}

View 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),
),
],
),
);
}
}

View 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(),
],
);
}
}

View 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),
),
],
),
);
}
}

View 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}'),
);
}
}

View 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);
}