mirror of
https://github.com/flutter/samples.git
synced 2026-06-13 01:39:16 +00:00
Flutter 3.29 beta (#2571)
This commit is contained in:
@@ -12,7 +12,8 @@ import '../../unsplash_access_key.dart';
|
||||
import '../unsplash/photo.dart';
|
||||
|
||||
final _unsplashHomepage = Uri.parse(
|
||||
'https://unsplash.com/?utm_source=$unsplashAppName&utm_medium=referral');
|
||||
'https://unsplash.com/?utm_source=$unsplashAppName&utm_medium=referral',
|
||||
);
|
||||
|
||||
typedef PhotoDetailsPhotoSaveCallback = void Function(Photo);
|
||||
|
||||
@@ -36,19 +37,22 @@ class _PhotoDetailsState extends State<PhotoDetails> {
|
||||
const Text('Photo by'),
|
||||
Link(
|
||||
uri: Uri.parse(
|
||||
'https://unsplash.com/@${widget.photo.user!.username}?utm_source=$unsplashAppName&utm_medium=referral'),
|
||||
builder: (context, followLink) => HyperlinkButton(
|
||||
onPressed: followLink,
|
||||
child: Text(widget.photo.user!.name),
|
||||
'https://unsplash.com/@${widget.photo.user!.username}?utm_source=$unsplashAppName&utm_medium=referral',
|
||||
),
|
||||
builder:
|
||||
(context, followLink) => HyperlinkButton(
|
||||
onPressed: followLink,
|
||||
child: Text(widget.photo.user!.name),
|
||||
),
|
||||
),
|
||||
const Text('on'),
|
||||
Link(
|
||||
uri: _unsplashHomepage,
|
||||
builder: (context, followLink) => HyperlinkButton(
|
||||
onPressed: followLink,
|
||||
child: const Text('Unsplash'),
|
||||
),
|
||||
builder:
|
||||
(context, followLink) => HyperlinkButton(
|
||||
onPressed: followLink,
|
||||
child: const Text('Unsplash'),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -35,33 +35,34 @@ class _PhotoSearchDialogState extends State<PhotoSearchDialog> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ContentDialog(
|
||||
title: const Text('Photo Search'),
|
||||
content: TextBox(
|
||||
autofocus: true,
|
||||
controller: _controller,
|
||||
onSubmitted: (content) {
|
||||
if (content.isNotEmpty) {
|
||||
widget.callback(content);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
FilledButton(
|
||||
onPressed: _searchEnabled
|
||||
title: const Text('Photo Search'),
|
||||
content: TextBox(
|
||||
autofocus: true,
|
||||
controller: _controller,
|
||||
onSubmitted: (content) {
|
||||
if (content.isNotEmpty) {
|
||||
widget.callback(content);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
FilledButton(
|
||||
onPressed:
|
||||
_searchEnabled
|
||||
? () {
|
||||
widget.callback(_controller.text);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
widget.callback(_controller.text);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
: null,
|
||||
child: const Text('Search'),
|
||||
),
|
||||
Button(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
],
|
||||
);
|
||||
child: const Text('Search'),
|
||||
),
|
||||
Button(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -26,16 +26,20 @@ class PolicyDialog extends StatelessWidget {
|
||||
TextSpan(
|
||||
text: 'https://policies.google.com/terms',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold, color: Colors.blue.normal),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
final url =
|
||||
Uri.parse('https://policies.google.com/terms');
|
||||
if (await url_launcher.canLaunchUrl(url)) {
|
||||
await url_launcher.launchUrl(url);
|
||||
}
|
||||
},
|
||||
)
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.blue.normal,
|
||||
),
|
||||
recognizer:
|
||||
TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
final url = Uri.parse(
|
||||
'https://policies.google.com/terms',
|
||||
);
|
||||
if (await url_launcher.canLaunchUrl(url)) {
|
||||
await url_launcher.launchUrl(url);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -48,15 +52,18 @@ class PolicyDialog extends StatelessWidget {
|
||||
TextSpan(
|
||||
text: 'https://unsplash.com/terms',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold, color: Colors.blue.normal),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
final url = Uri.parse('https://unsplash.com/terms');
|
||||
if (await url_launcher.canLaunchUrl(url)) {
|
||||
await url_launcher.launchUrl(url);
|
||||
}
|
||||
},
|
||||
)
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.blue.normal,
|
||||
),
|
||||
recognizer:
|
||||
TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
final url = Uri.parse('https://unsplash.com/terms');
|
||||
if (await url_launcher.canLaunchUrl(url)) {
|
||||
await url_launcher.launchUrl(url);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -173,9 +173,7 @@ class _SplitState extends State<Split> {
|
||||
child: SizedBox(
|
||||
width: isHorizontal ? Split.dividerMainAxisSize : width,
|
||||
height: isHorizontal ? height : Split.dividerMainAxisSize,
|
||||
child: Center(
|
||||
child: dragIndicator,
|
||||
),
|
||||
child: Center(child: dragIndicator),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
|
||||
@@ -9,9 +9,11 @@ import 'package:url_launcher/url_launcher.dart';
|
||||
import '../../unsplash_access_key.dart';
|
||||
|
||||
final _unsplashHomepage = Uri.parse(
|
||||
'https://unsplash.com/?utm_source=${Uri.encodeFull(unsplashAppName)}&utm_medium=referral');
|
||||
'https://unsplash.com/?utm_source=${Uri.encodeFull(unsplashAppName)}&utm_medium=referral',
|
||||
);
|
||||
final _unsplashPrivacyPolicy = Uri.parse(
|
||||
'https://unsplash.com/privacy?utm_source=${Uri.encodeFull(unsplashAppName)}&utm_medium=referral');
|
||||
'https://unsplash.com/privacy?utm_source=${Uri.encodeFull(unsplashAppName)}&utm_medium=referral',
|
||||
);
|
||||
|
||||
class UnsplashNotice extends StatefulWidget {
|
||||
const UnsplashNotice({super.key, required this.child});
|
||||
@@ -29,14 +31,17 @@ class _UnsplashNoticeState extends State<UnsplashNotice> {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return _UnsplashDialog(accepted: () {
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return _UnsplashDialog(
|
||||
accepted: () {
|
||||
setState(() {
|
||||
noticeAccepted = true;
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -56,50 +61,53 @@ class _UnsplashDialog extends StatelessWidget {
|
||||
title: const Text('Unsplash Notice'),
|
||||
content: RichText(
|
||||
text: TextSpan(
|
||||
text: 'This is a sample desktop application provided by Google'
|
||||
' that enables you to search ',
|
||||
style: const TextStyle(color: Colors.grey),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'Unsplash',
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
if (!await launchUrl(_unsplashHomepage)) {
|
||||
throw 'Could not launch $_unsplashHomepage';
|
||||
}
|
||||
},
|
||||
style: TextStyle(color: Colors.blue),
|
||||
),
|
||||
const TextSpan(
|
||||
text: ' for photographs that interest you. When you search'
|
||||
' for and interact with photos, Unsplash will collect'
|
||||
' information about you and your use of the Unsplash'
|
||||
' services. Learn more about ',
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'how Unsplash collects and uses data',
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
if (!await launchUrl(_unsplashPrivacyPolicy)) {
|
||||
throw 'Could not launch $_unsplashPrivacyPolicy';
|
||||
}
|
||||
},
|
||||
style: TextStyle(color: Colors.blue),
|
||||
),
|
||||
const TextSpan(
|
||||
text: '.',
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
]),
|
||||
text:
|
||||
'This is a sample desktop application provided by Google'
|
||||
' that enables you to search ',
|
||||
style: const TextStyle(color: Colors.grey),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'Unsplash',
|
||||
recognizer:
|
||||
TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
if (!await launchUrl(_unsplashHomepage)) {
|
||||
throw 'Could not launch $_unsplashHomepage';
|
||||
}
|
||||
},
|
||||
style: TextStyle(color: Colors.blue),
|
||||
),
|
||||
const TextSpan(
|
||||
text:
|
||||
' for photographs that interest you. When you search'
|
||||
' for and interact with photos, Unsplash will collect'
|
||||
' information about you and your use of the Unsplash'
|
||||
' services. Learn more about ',
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'how Unsplash collects and uses data',
|
||||
recognizer:
|
||||
TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
if (!await launchUrl(_unsplashPrivacyPolicy)) {
|
||||
throw 'Could not launch $_unsplashPrivacyPolicy';
|
||||
}
|
||||
},
|
||||
style: TextStyle(color: Colors.blue),
|
||||
),
|
||||
const TextSpan(text: '.', style: TextStyle(color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
Button(
|
||||
child: const Text('Got it'),
|
||||
onPressed: () {
|
||||
accepted();
|
||||
Navigator.pop(context);
|
||||
})
|
||||
child: const Text('Got it'),
|
||||
onPressed: () {
|
||||
accepted();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,30 +44,34 @@ class _UnsplashSearchContentState extends State<UnsplashSearchContent> {
|
||||
),
|
||||
),
|
||||
secondChild: Center(
|
||||
child: photoSearchModel.selectedPhoto != null
|
||||
? PhotoDetails(
|
||||
photo: photoSearchModel.selectedPhoto!,
|
||||
onPhotoSave: (photo) async {
|
||||
final saveLocation = await getSaveLocation(
|
||||
suggestedName: '${photo.id}.jpg',
|
||||
acceptedTypeGroups: [
|
||||
const XTypeGroup(
|
||||
label: 'JPG',
|
||||
extensions: ['jpg'],
|
||||
mimeTypes: ['image/jpeg'],
|
||||
),
|
||||
],
|
||||
);
|
||||
if (saveLocation != null) {
|
||||
final fileData =
|
||||
await photoSearchModel.download(photo: photo);
|
||||
final photoFile =
|
||||
XFile.fromData(fileData, mimeType: 'image/jpeg');
|
||||
await photoFile.saveTo(saveLocation.path);
|
||||
}
|
||||
},
|
||||
)
|
||||
: Container(),
|
||||
child:
|
||||
photoSearchModel.selectedPhoto != null
|
||||
? PhotoDetails(
|
||||
photo: photoSearchModel.selectedPhoto!,
|
||||
onPhotoSave: (photo) async {
|
||||
final saveLocation = await getSaveLocation(
|
||||
suggestedName: '${photo.id}.jpg',
|
||||
acceptedTypeGroups: [
|
||||
const XTypeGroup(
|
||||
label: 'JPG',
|
||||
extensions: ['jpg'],
|
||||
mimeTypes: ['image/jpeg'],
|
||||
),
|
||||
],
|
||||
);
|
||||
if (saveLocation != null) {
|
||||
final fileData = await photoSearchModel.download(
|
||||
photo: photo,
|
||||
);
|
||||
final photoFile = XFile.fromData(
|
||||
fileData,
|
||||
mimeType: 'image/jpeg',
|
||||
);
|
||||
await photoFile.saveTo(saveLocation.path);
|
||||
}
|
||||
},
|
||||
)
|
||||
: Container(),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -81,25 +85,26 @@ class _UnsplashSearchContentState extends State<UnsplashSearchContent> {
|
||||
|
||||
return TreeViewItem(
|
||||
content: Text(searchEntry.query),
|
||||
children: searchEntry.photos
|
||||
.map<TreeViewItem>(
|
||||
(photo) => TreeViewItem(
|
||||
content: Semantics(
|
||||
button: true,
|
||||
onTap: () => selectPhoto(photo),
|
||||
label: labelForPhoto(photo),
|
||||
excludeSemantics: true,
|
||||
child: GestureDetector(
|
||||
onTap: () => selectPhoto(photo),
|
||||
child: Text(
|
||||
labelForPhoto(photo),
|
||||
style: const TextStyle(color: Colors.black),
|
||||
children:
|
||||
searchEntry.photos
|
||||
.map<TreeViewItem>(
|
||||
(photo) => TreeViewItem(
|
||||
content: Semantics(
|
||||
button: true,
|
||||
onTap: () => selectPhoto(photo),
|
||||
label: labelForPhoto(photo),
|
||||
excludeSemantics: true,
|
||||
child: GestureDetector(
|
||||
onTap: () => selectPhoto(photo),
|
||||
child: Text(
|
||||
labelForPhoto(photo),
|
||||
style: const TextStyle(color: Colors.black),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user