[Gallery] Implement Fortnightly study (#304)

pull/311/head
rami-a 5 years ago committed by GitHub
parent eceff0ae62
commit f8a122903b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

@ -3460,6 +3460,182 @@ class GalleryLocalizations {
'When text is pressed the banner widget will be removed from the screen.');
}
String get fortnightlyDescription {
return Intl.message('A news app',
locale: _localeName,
name: 'fortnightlyDescription',
desc: r'Study description for Fortnightly.');
}
String get fortnightlyHeadlineArmy {
return Intl.message('Reforming The Green Army From Within',
locale: _localeName,
name: 'fortnightlyHeadlineArmy',
desc: r'Headline for a news article about the green army.');
}
String get fortnightlyHeadlineBees {
return Intl.message('Farmland Bees In Short Supply',
locale: _localeName,
name: 'fortnightlyHeadlineBees',
desc: r'Headline for a news article about bees.');
}
String get fortnightlyHeadlineFabrics {
return Intl.message('Designers Use Tech To Make Futuristic Fabrics',
locale: _localeName,
name: 'fortnightlyHeadlineFabrics',
desc: r'Headline for a news article about fabric.');
}
String get fortnightlyHeadlineFeminists {
return Intl.message('Feminists Take On Partisanship',
locale: _localeName,
name: 'fortnightlyHeadlineFeminists',
desc: r'Headline for a news article about feminists and partisanship.');
}
String get fortnightlyHeadlineGasoline {
return Intl.message('The Future of Gasoline',
locale: _localeName,
name: 'fortnightlyHeadlineGasoline',
desc: r'Headline for a news article about gasoline.');
}
String get fortnightlyHeadlineHealthcare {
return Intl.message('The Quiet, Yet Powerful Healthcare Revolution',
locale: _localeName,
name: 'fortnightlyHeadlineHealthcare',
desc: r'Headline for a news article about healthcare.');
}
String get fortnightlyHeadlineStocks {
return Intl.message('As Stocks Stagnate, Many Look To Currency',
locale: _localeName,
name: 'fortnightlyHeadlineStocks',
desc: r'Headline for a news article about stocks.');
}
String get fortnightlyHeadlineWar {
return Intl.message('Divided American Lives During War',
locale: _localeName,
name: 'fortnightlyHeadlineWar',
desc: r'Headline for a news article about war.');
}
String get fortnightlyLatestUpdates {
return Intl.message('Latest Updates',
locale: _localeName,
name: 'fortnightlyLatestUpdates',
desc: r'Title for news section regarding the latest updates.');
}
String get fortnightlyMenuBusiness {
return Intl.message('Business',
locale: _localeName,
name: 'fortnightlyMenuBusiness',
desc: r'Menu item for the business news section of the news app.');
}
String get fortnightlyMenuCulture {
return Intl.message('Culture',
locale: _localeName,
name: 'fortnightlyMenuCulture',
desc: r'Menu item for the culture news section of the news app.');
}
String get fortnightlyMenuFrontPage {
return Intl.message('Front Page',
locale: _localeName,
name: 'fortnightlyMenuFrontPage',
desc: r'Menu item for the front page of the news app.');
}
String get fortnightlyMenuPolitics {
return Intl.message('Politics',
locale: _localeName,
name: 'fortnightlyMenuPolitics',
desc: r'Menu item for the political news section of the news app.');
}
String get fortnightlyMenuScience {
return Intl.message('Science',
locale: _localeName,
name: 'fortnightlyMenuScience',
desc: r'Menu item for the science news section of the news app.');
}
String get fortnightlyMenuSports {
return Intl.message('Sports',
locale: _localeName,
name: 'fortnightlyMenuSports',
desc: r'Menu item for the sports news section of the news app.');
}
String get fortnightlyMenuTech {
return Intl.message('Tech',
locale: _localeName,
name: 'fortnightlyMenuTech',
desc: r'Menu item for the tech news section of the news app.');
}
String get fortnightlyMenuTravel {
return Intl.message('Travel',
locale: _localeName,
name: 'fortnightlyMenuTravel',
desc: r'Menu item for the travel news section of the news app.');
}
String get fortnightlyMenuUS {
return Intl.message('US',
locale: _localeName,
name: 'fortnightlyMenuUS',
desc: r'Menu item for the United States news section of the news app.');
}
String get fortnightlyMenuWorld {
return Intl.message('World',
locale: _localeName,
name: 'fortnightlyMenuWorld',
desc: r'Menu item for the world news section of the news app.');
}
String get fortnightlyTrendingGreenArmy {
return Intl.message('GreenArmy',
locale: _localeName,
name: 'fortnightlyTrendingGreenArmy',
desc: r'Hashtag for the green army trending topic of the news app.');
}
String get fortnightlyTrendingHealthcareRevolution {
return Intl.message('HealthcareRevolution',
locale: _localeName,
name: 'fortnightlyTrendingHealthcareRevolution',
desc:
r'Hashtag for the healthcare revolution trending topic of the news app.');
}
String get fortnightlyTrendingReform {
return Intl.message('Reform',
locale: _localeName,
name: 'fortnightlyTrendingReform',
desc: r'Hashtag for the reform trending topic of the news app.');
}
String get fortnightlyTrendingStocks {
return Intl.message('Stocks',
locale: _localeName,
name: 'fortnightlyTrendingStocks',
desc: r'Hashtag for the stocks trending topic of the news app.');
}
String get fortnightlyTrendingTechDesign {
return Intl.message('TechDesign',
locale: _localeName,
name: 'fortnightlyTrendingTechDesign',
desc: r'Hashtag for the tech design trending topic of the news app.');
}
String get homeCategoryReference {
return Intl.message('STYLES & OTHER',
locale: _localeName,

@ -123,6 +123,10 @@
"@shrineDescription": {
"description": "Study description for Shrine."
},
"fortnightlyDescription": "A news app",
"@fortnightlyDescription": {
"description": "Study description for Fortnightly."
},
"rallyDescription": "A personal finance app",
"@rallyDescription": {
"description": "Study description for Rally."
@ -2728,5 +2732,101 @@
"craneEat10SemanticLabel": "Woman holding huge pastrami sandwich",
"@craneEat10SemanticLabel": {
"description": "Semantic label for an image."
},
"fortnightlyMenuFrontPage": "Front Page",
"@fortnightlyMenuFrontPage": {
"description": "Menu item for the front page of the news app."
},
"fortnightlyMenuWorld": "World",
"@fortnightlyMenuWorld": {
"description": "Menu item for the world news section of the news app."
},
"fortnightlyMenuUS": "US",
"@fortnightlyMenuUS": {
"description": "Menu item for the United States news section of the news app."
},
"fortnightlyMenuPolitics": "Politics",
"@fortnightlyMenuPolitics": {
"description": "Menu item for the political news section of the news app."
},
"fortnightlyMenuBusiness": "Business",
"@fortnightlyMenuBusiness": {
"description": "Menu item for the business news section of the news app."
},
"fortnightlyMenuTech": "Tech",
"@fortnightlyMenuTech": {
"description": "Menu item for the tech news section of the news app."
},
"fortnightlyMenuScience": "Science",
"@fortnightlyMenuScience": {
"description": "Menu item for the science news section of the news app."
},
"fortnightlyMenuSports": "Sports",
"@fortnightlyMenuSports": {
"description": "Menu item for the sports news section of the news app."
},
"fortnightlyMenuTravel": "Travel",
"@fortnightlyMenuTravel": {
"description": "Menu item for the travel news section of the news app."
},
"fortnightlyMenuCulture": "Culture",
"@fortnightlyMenuCulture": {
"description": "Menu item for the culture news section of the news app."
},
"fortnightlyTrendingTechDesign": "TechDesign",
"@fortnightlyTrendingTechDesign": {
"description": "Hashtag for the tech design trending topic of the news app."
},
"fortnightlyTrendingReform": "Reform",
"@fortnightlyTrendingReform": {
"description": "Hashtag for the reform trending topic of the news app."
},
"fortnightlyTrendingHealthcareRevolution": "HealthcareRevolution",
"@fortnightlyTrendingHealthcareRevolution": {
"description": "Hashtag for the healthcare revolution trending topic of the news app."
},
"fortnightlyTrendingGreenArmy": "GreenArmy",
"@fortnightlyTrendingGreenArmy": {
"description": "Hashtag for the green army trending topic of the news app."
},
"fortnightlyTrendingStocks": "Stocks",
"@fortnightlyTrendingStocks": {
"description": "Hashtag for the stocks trending topic of the news app."
},
"fortnightlyLatestUpdates": "Latest Updates",
"@fortnightlyLatestUpdates": {
"description": "Title for news section regarding the latest updates."
},
"fortnightlyHeadlineHealthcare": "The Quiet, Yet Powerful Healthcare Revolution",
"@fortnightlyHeadlineHealthcare": {
"description": "Headline for a news article about healthcare."
},
"fortnightlyHeadlineWar": "Divided American Lives During War",
"@fortnightlyHeadlineWar": {
"description": "Headline for a news article about war."
},
"fortnightlyHeadlineGasoline": "The Future of Gasoline",
"@fortnightlyHeadlineGasoline": {
"description": "Headline for a news article about gasoline."
},
"fortnightlyHeadlineArmy": "Reforming The Green Army From Within",
"@fortnightlyHeadlineArmy": {
"description": "Headline for a news article about the green army."
},
"fortnightlyHeadlineStocks": "As Stocks Stagnate, Many Look To Currency",
"@fortnightlyHeadlineStocks": {
"description": "Headline for a news article about stocks."
},
"fortnightlyHeadlineFabrics": "Designers Use Tech To Make Futuristic Fabrics",
"@fortnightlyHeadlineFabrics": {
"description": "Headline for a news article about fabric."
},
"fortnightlyHeadlineFeminists": "Feminists Take On Partisanship",
"@fortnightlyHeadlineFeminists": {
"description": "Headline for a news article about feminists and partisanship."
},
"fortnightlyHeadlineBees": "Farmland Bees In Short Supply",
"@fortnightlyHeadlineBees": {
"description": "Headline for a news article about bees."
}
}

@ -113,6 +113,10 @@
name="shrineDescription"
description="Study description for Shrine."
>A fashionable retail app</string>
<string
name="fortnightlyDescription"
description="Study description for Fortnightly."
>A news app</string>
<string
name="rallyDescription"
description="Study description for Rally."
@ -2533,4 +2537,100 @@
name="craneEat10SemanticLabel"
description="Semantic label for an image."
>Woman holding huge pastrami sandwich</string>
<string
name="fortnightlyMenuFrontPage"
description="Menu item for the front page of the news app."
>Front Page</string>
<string
name="fortnightlyMenuWorld"
description="Menu item for the world news section of the news app."
>World</string>
<string
name="fortnightlyMenuUS"
description="Menu item for the United States news section of the news app."
>US</string>
<string
name="fortnightlyMenuPolitics"
description="Menu item for the political news section of the news app."
>Politics</string>
<string
name="fortnightlyMenuBusiness"
description="Menu item for the business news section of the news app."
>Business</string>
<string
name="fortnightlyMenuTech"
description="Menu item for the tech news section of the news app."
>Tech</string>
<string
name="fortnightlyMenuScience"
description="Menu item for the science news section of the news app."
>Science</string>
<string
name="fortnightlyMenuSports"
description="Menu item for the sports news section of the news app."
>Sports</string>
<string
name="fortnightlyMenuTravel"
description="Menu item for the travel news section of the news app."
>Travel</string>
<string
name="fortnightlyMenuCulture"
description="Menu item for the culture news section of the news app."
>Culture</string>
<string
name="fortnightlyTrendingTechDesign"
description="Hashtag for the tech design trending topic of the news app."
>TechDesign</string>
<string
name="fortnightlyTrendingReform"
description="Hashtag for the reform trending topic of the news app."
>Reform</string>
<string
name="fortnightlyTrendingHealthcareRevolution"
description="Hashtag for the healthcare revolution trending topic of the news app."
>HealthcareRevolution</string>
<string
name="fortnightlyTrendingGreenArmy"
description="Hashtag for the green army trending topic of the news app."
>GreenArmy</string>
<string
name="fortnightlyTrendingStocks"
description="Hashtag for the stocks trending topic of the news app."
>Stocks</string>
<string
name="fortnightlyLatestUpdates"
description="Title for news section regarding the latest updates."
>Latest Updates</string>
<string
name="fortnightlyHeadlineHealthcare"
description="Headline for a news article about healthcare."
>The Quiet, Yet Powerful Healthcare Revolution</string>
<string
name="fortnightlyHeadlineWar"
description="Headline for a news article about war."
>Divided American Lives During War</string>
<string
name="fortnightlyHeadlineGasoline"
description="Headline for a news article about gasoline."
>The Future of Gasoline</string>
<string
name="fortnightlyHeadlineArmy"
description="Headline for a news article about the green army."
>Reforming The Green Army From Within</string>
<string
name="fortnightlyHeadlineStocks"
description="Headline for a news article about stocks."
>As Stocks Stagnate, Many Look To Currency</string>
<string
name="fortnightlyHeadlineFabrics"
description="Headline for a news article about fabric."
>Designers Use Tech To Make Futuristic Fabrics</string>
<string
name="fortnightlyHeadlineFeminists"
description="Headline for a news article about feminists and partisanship."
>Feminists Take On Partisanship</string>
<string
name="fortnightlyHeadlineBees"
description="Headline for a news article about bees."
>Farmland Bees In Short Supply</string>
</resources>

@ -898,6 +898,51 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Set backup account"),
"dialogShow": MessageLookupByLibrary.simpleMessage("SHOW DIALOG"),
"dismiss": MessageLookupByLibrary.simpleMessage("DISMISS"),
"fortnightlyDescription":
MessageLookupByLibrary.simpleMessage("A news app"),
"fortnightlyHeadlineArmy": MessageLookupByLibrary.simpleMessage(
"Reforming The Green Army From Within"),
"fortnightlyHeadlineBees": MessageLookupByLibrary.simpleMessage(
"Farmland Bees In Short Supply"),
"fortnightlyHeadlineFabrics": MessageLookupByLibrary.simpleMessage(
"Designers Use Tech To Make Futuristic Fabrics"),
"fortnightlyHeadlineFeminists": MessageLookupByLibrary.simpleMessage(
"Feminists Take On Partisanship"),
"fortnightlyHeadlineGasoline":
MessageLookupByLibrary.simpleMessage("The Future of Gasoline"),
"fortnightlyHeadlineHealthcare": MessageLookupByLibrary.simpleMessage(
"The Quiet, Yet Powerful Healthcare Revolution"),
"fortnightlyHeadlineStocks": MessageLookupByLibrary.simpleMessage(
"As Stocks Stagnate, Many Look To Currency"),
"fortnightlyHeadlineWar": MessageLookupByLibrary.simpleMessage(
"Divided American Lives During War"),
"fortnightlyLatestUpdates":
MessageLookupByLibrary.simpleMessage("Latest Updates"),
"fortnightlyMenuBusiness":
MessageLookupByLibrary.simpleMessage("Business"),
"fortnightlyMenuCulture":
MessageLookupByLibrary.simpleMessage("Culture"),
"fortnightlyMenuFrontPage":
MessageLookupByLibrary.simpleMessage("Front Page"),
"fortnightlyMenuPolitics":
MessageLookupByLibrary.simpleMessage("Politics"),
"fortnightlyMenuScience":
MessageLookupByLibrary.simpleMessage("Science"),
"fortnightlyMenuSports": MessageLookupByLibrary.simpleMessage("Sports"),
"fortnightlyMenuTech": MessageLookupByLibrary.simpleMessage("Tech"),
"fortnightlyMenuTravel": MessageLookupByLibrary.simpleMessage("Travel"),
"fortnightlyMenuUS": MessageLookupByLibrary.simpleMessage("US"),
"fortnightlyMenuWorld": MessageLookupByLibrary.simpleMessage("World"),
"fortnightlyTrendingGreenArmy":
MessageLookupByLibrary.simpleMessage("GreenArmy"),
"fortnightlyTrendingHealthcareRevolution":
MessageLookupByLibrary.simpleMessage("HealthcareRevolution"),
"fortnightlyTrendingReform":
MessageLookupByLibrary.simpleMessage("Reform"),
"fortnightlyTrendingStocks":
MessageLookupByLibrary.simpleMessage("Stocks"),
"fortnightlyTrendingTechDesign":
MessageLookupByLibrary.simpleMessage("TechDesign"),
"homeCategoryReference":
MessageLookupByLibrary.simpleMessage("STYLES & OTHER"),
"homeHeaderCategories":

@ -19,6 +19,7 @@ import 'package:gallery/pages/settings.dart';
import 'package:gallery/pages/splash.dart';
import 'package:gallery/studies/crane/app.dart';
import 'package:gallery/studies/crane/colors.dart';
import 'package:gallery/studies/fortnightly/app.dart';
import 'package:gallery/studies/rally/app.dart';
import 'package:gallery/studies/rally/colors.dart';
import 'package:gallery/studies/shrine/app.dart';
@ -30,11 +31,11 @@ const _carouselItemMargin = 8.0;
const _horizontalDesktopPadding = 81.0;
const _carouselHeightMin = 200.0 + 2 * _carouselItemMargin;
const String shrineTitle = 'Shrine';
const String rallyTitle = 'Rally';
const String craneTitle = 'Crane';
const String homeCategoryMaterial = 'MATERIAL';
const String homeCategoryCupertino = 'CUPERTINO';
const shrineTitle = 'Shrine';
const rallyTitle = 'Rally';
const craneTitle = 'Crane';
const homeCategoryMaterial = 'MATERIAL';
const homeCategoryCupertino = 'CUPERTINO';
class ToggleSplashNotification extends Notification {}
@ -42,6 +43,7 @@ class NavigatorKeys {
static final shrine = GlobalKey<NavigatorState>();
static final rally = GlobalKey<NavigatorState>();
static final crane = GlobalKey<NavigatorState>();
static final fortnightly = GlobalKey<NavigatorState>();
static final starter = GlobalKey<NavigatorState>();
}
@ -78,6 +80,13 @@ class HomePage extends StatelessWidget {
study: CraneApp(navigatorKey: NavigatorKeys.crane),
navigatorKey: NavigatorKeys.crane,
),
_CarouselCard(
title: fortnightlyTitle,
subtitle: GalleryLocalizations.of(context).fortnightlyDescription,
// TODO: Provide asset for study banner.
study: FortnightlyApp(navigatorKey: NavigatorKeys.fortnightly),
navigatorKey: NavigatorKeys.fortnightly,
),
_CarouselCard(
title: GalleryLocalizations.of(context).starterAppTitle,
subtitle: GalleryLocalizations.of(context).starterAppDescription,
@ -743,6 +752,7 @@ class _CarouselCard extends StatelessWidget {
elevation: 4,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
clipBehavior: Clip.antiAlias,
color: Colors.grey,
child: InkWell(
onTap: () {
Navigator.of(context).push<void>(
@ -757,10 +767,11 @@ class _CarouselCard extends StatelessWidget {
child: Stack(
fit: StackFit.expand,
children: [
Ink.image(
image: AssetImage(asset),
fit: BoxFit.cover,
),
if (asset != null)
Ink.image(
image: AssetImage(asset),
fit: BoxFit.cover,
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(16, 0, 16, 16),
child: Column(

@ -0,0 +1,163 @@
// Copyright 2019 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/material.dart';
import 'package:gallery/data/gallery_options.dart';
import 'package:gallery/layout/adaptive.dart';
import 'package:gallery/layout/text_scale.dart';
import 'package:gallery/l10n/gallery_localizations.dart';
import 'package:gallery/studies/fortnightly/shared.dart';
const fortnightlyTitle = 'Fortnightly';
class FortnightlyApp extends StatelessWidget {
const FortnightlyApp({Key key, this.navigatorKey}) : super(key: key);
final GlobalKey<NavigatorState> navigatorKey;
@override
Widget build(BuildContext context) {
final home = isDisplayDesktop(context)
? _FortnightlyHomeDesktop()
: _FortnightlyHomeMobile();
return MaterialApp(
navigatorKey: navigatorKey,
debugShowCheckedModeBanner: false,
theme: buildTheme(context).copyWith(
platform: GalleryOptions.of(context).platform,
),
home: ApplyTextOptions(child: home),
// L10n settings.
localizationsDelegates: GalleryLocalizations.localizationsDelegates,
supportedLocales: GalleryLocalizations.supportedLocales,
locale: GalleryOptions.of(context).locale,
);
}
}
class _FortnightlyHomeMobile extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: Drawer(
child: SafeArea(
child: NavigationMenu(isCloseable: true),
),
),
appBar: AppBar(
title: Semantics(
label: fortnightlyTitle,
child: Image.asset(
'assets/fortnightly/fortnightly_title.png',
excludeFromSemantics: true,
),
),
actions: [
IconButton(
icon: const Icon(Icons.search),
tooltip: GalleryLocalizations.of(context).shrineTooltipSearch,
onPressed: () {},
),
],
),
body: SafeArea(
child: ListView(
children: [
HashtagBar(),
for (final item in buildArticlePreviewItems(context))
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: item,
),
],
),
),
);
}
}
class _FortnightlyHomeDesktop extends StatelessWidget {
@override
Widget build(BuildContext context) {
final menuWidth = 200.0;
final spacer = SizedBox(width: 20);
final headerHeight = 40 * reducedTextScale(context);
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
SizedBox(
height: headerHeight,
child: Row(
children: [
Container(
width: menuWidth,
alignment: AlignmentDirectional.centerStart,
margin: EdgeInsets.only(left: 12),
child: Semantics(
label: fortnightlyTitle,
child: Image.asset(
'assets/fortnightly/fortnightly_title.png',
excludeFromSemantics: true,
),
),
),
spacer,
Flexible(
flex: 2,
child: HashtagBar(),
),
spacer,
Flexible(
fit: FlexFit.tight,
child: Container(
alignment: AlignmentDirectional.centerEnd,
child: IconButton(
icon: const Icon(Icons.search),
tooltip: GalleryLocalizations.of(context)
.shrineTooltipSearch,
onPressed: () {},
),
),
),
],
),
),
Flexible(
child: Row(
children: [
SizedBox(
width: menuWidth,
child: NavigationMenu(),
),
spacer,
Flexible(
flex: 2,
child: ListView(
children: buildArticlePreviewItems(context),
),
),
spacer,
Flexible(
flex: 1,
fit: FlexFit.tight,
child: ListView(
children: [
...buildStockItems(context),
SizedBox(height: 32),
...buildVideoPreviewItems(context),
],
),
),
],
),
),
],
),
),
);
}
}

@ -0,0 +1,549 @@
// Copyright 2019 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/material.dart';
import 'package:gallery/data/gallery_options.dart';
import 'package:gallery/layout/text_scale.dart';
import 'package:gallery/l10n/gallery_localizations.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
class ArticleData {
ArticleData({this.imageUrl, this.category, this.title, this.snippet});
final String imageUrl;
final String category;
final String title;
final String snippet;
}
class HorizontalArticlePreview extends StatelessWidget {
HorizontalArticlePreview({this.data, this.minutes});
final ArticleData data;
final int minutes;
@override
Widget build(BuildContext context) {
TextTheme textTheme = Theme.of(context).textTheme;
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
data.category,
style: textTheme.subhead,
),
SizedBox(height: 12),
Text(
data.title,
style: textTheme.headline.copyWith(fontSize: 16),
),
],
),
),
if (minutes != null) ...[
Text(
GalleryLocalizations.of(context).craneMinutes(minutes),
style: textTheme.body2,
),
SizedBox(width: 8),
],
Image.asset(
data.imageUrl,
fit: BoxFit.cover,
excludeFromSemantics: true,
),
],
);
}
}
class VerticalArticlePreview extends StatelessWidget {
VerticalArticlePreview({
this.data,
this.width,
this.headlineTextStyle,
this.showSnippet = false,
});
final ArticleData data;
final double width;
final TextStyle headlineTextStyle;
final bool showSnippet;
@override
Widget build(BuildContext context) {
TextTheme textTheme = Theme.of(context).textTheme;
return SizedBox(
width: width ?? double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: double.infinity,
child: Image.asset(
data.imageUrl,
fit: BoxFit.fitWidth,
excludeFromSemantics: true,
),
),
SizedBox(height: 12),
Text(
data.category,
style: textTheme.subhead,
),
SizedBox(height: 12),
Text(
data.title,
style: headlineTextStyle ?? textTheme.headline,
),
if (showSnippet) ...[
SizedBox(height: 4),
Text(
data.snippet,
style: textTheme.body1,
),
],
],
),
);
}
}
List<Widget> buildArticlePreviewItems(BuildContext context) {
Widget articleDivider = Container(
margin: const EdgeInsets.symmetric(vertical: 16),
color: Colors.black.withOpacity(0.07),
height: 1,
);
Widget sectionDivider = Container(
margin: const EdgeInsets.symmetric(vertical: 16),
color: Colors.black.withOpacity(0.2),
height: 1,
);
TextTheme textTheme = Theme.of(context).textTheme;
return <Widget>[
VerticalArticlePreview(
data: ArticleData(
imageUrl: 'assets/fortnightly/fortnightly_healthcare.jpg',
category:
GalleryLocalizations.of(context).fortnightlyMenuWorld.toUpperCase(),
title: GalleryLocalizations.of(context).fortnightlyHeadlineHealthcare,
),
headlineTextStyle: textTheme.headline.copyWith(fontSize: 20),
),
articleDivider,
HorizontalArticlePreview(
data: ArticleData(
imageUrl: 'assets/fortnightly/fortnightly_war.png',
category: GalleryLocalizations.of(context)
.fortnightlyMenuPolitics
.toUpperCase(),
title: GalleryLocalizations.of(context).fortnightlyHeadlineWar,
),
),
articleDivider,
HorizontalArticlePreview(
data: ArticleData(
imageUrl: 'assets/fortnightly/fortnightly_gas.png',
category:
GalleryLocalizations.of(context).fortnightlyMenuTech.toUpperCase(),
title: GalleryLocalizations.of(context).fortnightlyHeadlineGasoline,
),
),
sectionDivider,
Text(
GalleryLocalizations.of(context).fortnightlyLatestUpdates,
style: textTheme.title,
),
articleDivider,
HorizontalArticlePreview(
data: ArticleData(
imageUrl: 'assets/fortnightly/fortnightly_army.png',
category: GalleryLocalizations.of(context)
.fortnightlyMenuPolitics
.toUpperCase(),
title: GalleryLocalizations.of(context).fortnightlyHeadlineArmy,
),
minutes: 2,
),
articleDivider,
HorizontalArticlePreview(
data: ArticleData(
imageUrl: 'assets/fortnightly/fortnightly_stocks.png',
category:
GalleryLocalizations.of(context).fortnightlyMenuWorld.toUpperCase(),
title: GalleryLocalizations.of(context).fortnightlyHeadlineStocks,
),
minutes: 5,
),
articleDivider,
HorizontalArticlePreview(
data: ArticleData(
imageUrl: 'assets/fortnightly/fortnightly_fabrics.png',
category:
GalleryLocalizations.of(context).fortnightlyMenuTech.toUpperCase(),
title: GalleryLocalizations.of(context).fortnightlyHeadlineFabrics,
),
minutes: 4,
),
articleDivider,
];
}
class HashtagBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
final verticalDivider = Container(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
color: Colors.black.withOpacity(0.1),
width: 1,
);
final textTheme = Theme.of(context).textTheme;
final height = 32 * reducedTextScale(context);
return SizedBox(
height: height,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
SizedBox(width: 16),
Center(
child: Text(
'#${GalleryLocalizations.of(context).fortnightlyTrendingTechDesign}',
style: textTheme.subtitle,
),
),
verticalDivider,
Center(
child: Text(
'#${GalleryLocalizations.of(context).fortnightlyTrendingReform}',
style: textTheme.subtitle,
),
),
verticalDivider,
Center(
child: Text(
'#${GalleryLocalizations.of(context).fortnightlyTrendingHealthcareRevolution}',
style: textTheme.subtitle,
),
),
verticalDivider,
Center(
child: Text(
'#${GalleryLocalizations.of(context).fortnightlyTrendingGreenArmy}',
style: textTheme.subtitle,
),
),
verticalDivider,
Center(
child: Text(
'#${GalleryLocalizations.of(context).fortnightlyTrendingStocks}',
style: textTheme.subtitle,
),
),
verticalDivider,
],
),
);
}
}
class NavigationMenu extends StatelessWidget {
NavigationMenu({this.isCloseable = false});
final bool isCloseable;
@override
Widget build(BuildContext context) {
return ListView(
children: [
if (isCloseable)
Row(
children: [
IconButton(
icon: Icon(Icons.close),
tooltip: MaterialLocalizations.of(context).closeButtonTooltip,
onPressed: () => Navigator.pop(context),
),
Image.asset(
'assets/fortnightly/fortnightly_title.png',
excludeFromSemantics: true,
),
],
),
SizedBox(height: 32),
MenuItem(
GalleryLocalizations.of(context).fortnightlyMenuFrontPage,
header: true,
),
MenuItem(GalleryLocalizations.of(context).fortnightlyMenuWorld),
MenuItem(GalleryLocalizations.of(context).fortnightlyMenuUS),
MenuItem(GalleryLocalizations.of(context).fortnightlyMenuPolitics),
MenuItem(GalleryLocalizations.of(context).fortnightlyMenuBusiness),
MenuItem(GalleryLocalizations.of(context).fortnightlyMenuTech),
MenuItem(GalleryLocalizations.of(context).fortnightlyMenuScience),
MenuItem(GalleryLocalizations.of(context).fortnightlyMenuSports),
MenuItem(GalleryLocalizations.of(context).fortnightlyMenuTravel),
MenuItem(GalleryLocalizations.of(context).fortnightlyMenuCulture),
],
);
}
}
class MenuItem extends StatelessWidget {
MenuItem(this.title, {this.header = false});
final String title;
final bool header;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
children: [
Container(
width: 32,
alignment: Alignment.centerLeft,
child: header ? null : Icon(Icons.arrow_drop_down),
),
Expanded(
child: Text(
title,
style: Theme.of(context).textTheme.subhead.copyWith(
fontWeight: header ? FontWeight.w700 : FontWeight.w600,
fontSize: 16,
),
),
),
],
),
);
}
}
class StockItem extends StatelessWidget {
StockItem({this.ticker, this.price, this.percent});
final String ticker;
final String price;
final double percent;
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
final percentFormat = NumberFormat.decimalPercentPattern(
locale: GalleryOptions.of(context).locale.toString(),
decimalDigits: 2,
);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(ticker, style: textTheme.subhead),
SizedBox(height: 2),
Row(
children: [
Expanded(
child: Text(
price,
style: textTheme.subtitle.copyWith(
color: textTheme.subtitle.color.withOpacity(0.75),
),
),
),
Text(
percent > 0 ? '+' : '-',
style: textTheme.subtitle.copyWith(
fontSize: 12,
color: percent > 0 ? Color(0xff20CF63) : Color(0xff661FFF),
),
),
SizedBox(width: 4),
Text(
percentFormat.format(percent.abs() / 100),
style: textTheme.caption.copyWith(
fontSize: 12,
color: textTheme.subtitle.color.withOpacity(0.75),
),
),
],
)
],
);
}
}
List<Widget> buildStockItems(BuildContext context) {
Widget articleDivider = Container(
margin: EdgeInsets.symmetric(vertical: 16),
color: Colors.black.withOpacity(0.07),
height: 1,
);
return <Widget>[
SizedBox(
width: double.infinity,
child: Image.asset(
'assets/fortnightly/fortnightly_chart.png',
fit: BoxFit.contain,
excludeFromSemantics: true,
),
),
articleDivider,
StockItem(
ticker: 'DIJA',
price: '7,031.21',
percent: -0.48,
),
articleDivider,
StockItem(
ticker: 'SP',
price: '1,967.84',
percent: -0.23,
),
articleDivider,
StockItem(
ticker: 'Nasdaq',
price: '6,211.46',
percent: 0.52,
),
articleDivider,
StockItem(
ticker: 'Nikkei',
price: '5,891',
percent: 1.16,
),
articleDivider,
StockItem(
ticker: 'DJ Total',
price: '89.02',
percent: 0.80,
),
articleDivider,
];
}
class VideoPreview extends StatelessWidget {
VideoPreview({this.data, this.time});
final ArticleData data;
final String time;
@override
Widget build(BuildContext context) {
TextTheme textTheme = Theme.of(context).textTheme;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: double.infinity,
child: Image.asset(
data.imageUrl,
fit: BoxFit.contain,
excludeFromSemantics: true,
),
),
SizedBox(height: 4),
Row(
children: [
Expanded(
child: Text(data.category, style: textTheme.subhead),
),
Text(time, style: textTheme.body2)
],
),
SizedBox(height: 4),
Text(data.title, style: textTheme.headline.copyWith(fontSize: 16)),
],
);
}
}
List<Widget> buildVideoPreviewItems(BuildContext context) {
return <Widget>[
VideoPreview(
data: ArticleData(
imageUrl: 'assets/fortnightly/fortnightly_feminists.jpg',
category: GalleryLocalizations.of(context)
.fortnightlyMenuPolitics
.toUpperCase(),
title: GalleryLocalizations.of(context).fortnightlyHeadlineFeminists,
),
time: '2:31',
),
SizedBox(height: 32),
VideoPreview(
data: ArticleData(
imageUrl: 'assets/fortnightly/fortnightly_bees.jpg',
category:
GalleryLocalizations.of(context).fortnightlyMenuUS.toUpperCase(),
title: GalleryLocalizations.of(context).fortnightlyHeadlineBees,
),
time: '1:37',
),
];
}
ThemeData buildTheme(BuildContext context) {
TextTheme textTheme = Theme.of(context).textTheme;
return ThemeData(
scaffoldBackgroundColor: Colors.white,
appBarTheme: AppBarTheme(
color: Colors.white,
elevation: 0,
iconTheme: IconTheme.of(context).copyWith(color: Colors.black),
),
highlightColor: Colors.transparent,
textTheme: textTheme.copyWith(
// preview snippet
body1: GoogleFonts.merriweather(
fontWeight: FontWeight.w300,
fontSize: 16,
textStyle: textTheme.body1,
),
// time in latest updates
body2: GoogleFonts.libreFranklin(
fontWeight: FontWeight.w500,
fontSize: 11,
color: Colors.black.withOpacity(0.5),
textStyle: textTheme.body2,
),
// preview headlines
headline: GoogleFonts.libreFranklin(
fontWeight: FontWeight.w500,
fontSize: 16,
textStyle: textTheme.headline,
),
// TODO: Use GoogleFonts.robotoCondensed when available
// (caption 2), preview category, stock ticker
subhead: textTheme.subhead.copyWith(
fontFamily: 'Roboto Condensed',
fontWeight: FontWeight.w700,
fontSize: 16,
),
subtitle: GoogleFonts.libreFranklin(
fontWeight: FontWeight.w400,
fontSize: 14,
textStyle: textTheme.subtitle,
),
// section titles: Top Highlights, Last Updated...
title: GoogleFonts.merriweather(
fontWeight: FontWeight.w700,
fontStyle: FontStyle.italic,
fontSize: 14,
textStyle: textTheme.title,
),
),
);
}

@ -48,6 +48,7 @@ flutter:
- packages/rally_assets/thumb.png
- assets/crane/logo/
- assets/crane/destinations/
- assets/fortnightly/
- packages/flutter_gallery_assets/places/india_chennai_flower_market.png
- packages/flutter_gallery_assets/places/india_thanjavur_market.png
- packages/flutter_gallery_assets/places/india_tanjore_bronze_works.png

Loading…
Cancel
Save