我正在AndroidStudio中使用Dart创建一个应用程序,并希望使用flutter_quill 10.1.6为文本页面创建工具栏(类似于docs/word/ention)
我使用10.1.4已经尝试了好几天,直到使用ChatGPT创建的工具栏。这是代码:
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' as quill;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Quill Editor Example'),
),
body: QuillEditorExample(),
),
);
}
}
class QuillEditorExample extends StatefulWidget {
@override
_QuillEditorExampleState createState() => _QuillEditorExampleState();
}
class _QuillEditorExampleState extends State<QuillEditorExample> {
final quill.QuillController _controller = quill.QuillController.basic();
@override
Widget build(BuildContext context) {
return Column(
children: [
quill.QuillToolbar.simple(
controller: _controller,
),
Expanded(
child: quill.QuillEditor(
controller: _controller,
scrollController: ScrollController(),
focusNode: FocusNode(),
),
),
],
);
}
}
这是ChatGPT编码的页面的屏幕截图。
如果我只想在我的应用程序中使用此工具栏中的某些按钮,如粗体、斜体、下划线、编号列表、字体大小和字体颜色,我该如何更改代码?我该怎么办?
在学习了所有这些之后,我想将其集成到我迄今为止编码的页面中(使用AI)。这是选项卡/页面的代码片段。
body: TabBarView(
controller: _tabController,
children: [
quill.QuillEditor.basic(
controller: _quillController,
),
我还附上了下面页面的整个代码:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:image_picker/image_picker.dart';
import 'package:photo_view/photo_view.dart';
import 'dart:io';
import 'dart:typed_data'; // Import dart:typed_data
import 'package:video_player/video_player.dart';
import 'package:video_thumbnail/video_thumbnail.dart'; // Import
import 'OpeningPage.dart';
import 'package:flutter_quill/flutter_quill.dart' as quill;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Insite',
theme: ThemeData(
primarySwatch: Colors.teal,
),
home: OpeningPage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
late TabController _tabController;
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final TextEditingController _notesController = TextEditingController();
final quill.QuillController _quillController = quill.QuillController.basic();
String _label = 'Untitled'; //Edit
@override
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
_loadLabel();
}
Future<void> _loadLabel() async {
DocumentSnapshot snapshot = await _firestore.collection('settings').doc('headerLabel').get();
if (snapshot.exists) {
setState(() {
_label = snapshot['label'];
});
}
}
Future<void> _saveLabel(String label) async {
await _firestore.collection('settings').doc('headerLabel').set({
'label': label,
});
setState(() {
_label = label;
});
}
@override
void dispose() {
_tabController.dispose();
_notesController.dispose();
super.dispose();
}
Future<void> _saveNoteToFirebase(String note) async {
await _firestore.collection('notes').add({
'note': note,
'date': DateTime.now().toString(),
'timestamp': FieldValue.serverTimestamp(),
});
}
Future<void> _uploadImage(File imageFile) async {
String fileName = DateTime.now().millisecondsSinceEpoch.toString();
UploadTask uploadTask = FirebaseStorage.instance.ref().child('images/$fileName').putFile(imageFile);
TaskSnapshot snapshot = await uploadTask;
String imageUrl = await snapshot.ref.getDownloadURL();
await _firestore.collection('images').add({
'imageUrl': imageUrl,
'label': 'Untitled',
'date': DateTime.now().toString(),
'time': DateTime.now().toString(),
'timestamp': FieldValue.serverTimestamp(),
});
}
Future<void> _uploadVideo(File videoFile) async {
String fileName = DateTime.now().millisecondsSinceEpoch.toString();
UploadTask uploadTask = FirebaseStorage.instance.ref().child('videos/$fileName').putFile(videoFile);
TaskSnapshot snapshot = await uploadTask;
String videoUrl = await snapshot.ref.getDownloadURL();
await _firestore.collection('videos').add({
'videoUrl': videoUrl,
'label': 'Untitled',
'date': DateTime.now().toString(),
'time': DateTime.now().toString(),
'timestamp': FieldValue.serverTimestamp(),
});
}
Future<void> getImage(ImageSource source) async {
final pickedFile = await ImagePicker().pickImage(source: source);
if (pickedFile != null) {
File imageFile = File(pickedFile.path);
_uploadImage(imageFile);
}
}
Future<void> getVideo(ImageSource source) async {
final pickedFile = await ImagePicker().pickVideo(source: source);
if (pickedFile != null) {
File videoFile = File(pickedFile.path);
_uploadVideo(videoFile);
}
}
Future<void> _deleteImage(String docId, String imageUrl) async {
try {
// Delete the image from Firebase Storage
await FirebaseStorage.instance.refFromURL(imageUrl).delete();
// Delete the document from Firestore
await _firestore.collection('images').doc(docId).delete();
} catch (e) {
print('Error deleting image: $e');
}
}
Future<void> _deleteVideo(String docId, String videoUrl) async {
try {
// Delete the video from Firebase Storage
await FirebaseStorage.instance.refFromURL(videoUrl).delete();
// Delete the document from Firestore
await _firestore.collection('videos').doc(docId).delete();
} catch (e) {
print('Error deleting video: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
expandedHeight: 200.0,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
titlePadding: EdgeInsets.only(left: 16, bottom: 16),
title: GestureDetector(
onTap: () async {
String? newLabel = await showDialog(
context: context,
builder: (BuildContext context) {
String labelText = _label;
return AlertDialog(
title: Text('Edit Label'),
content: TextField(
onChanged: (value) {
labelText = value;
},
decoration: InputDecoration(hintText: "Enter new label"),
),
actions: <Widget>[
TextButton(
child: Text('OK'),
onPressed: () {
Navigator.of(context).pop(labelText);
},
),
],
);
},
);
if (newLabel != null && newLabel.isNotEmpty) {
_saveLabel(newLabel);
// Update the label of the placeholder image
}
},
child: Text(
_label,
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
shadows: [
Shadow(
offset: Offset(0, 1),
blurRadius: 3,
color: Colors.black,
),
],
),
),
),
background: FutureBuilder(
future: _firestore.collection('images').orderBy('timestamp', descending: true).limit(1).get(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Center(child: Text('Something went wrong'));
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
String headerImageUrl = snapshot.data!.docs.isNotEmpty ? snapshot.data!.docs.first['imageUrl'] : '';
return Stack(
fit: StackFit.expand,
children: [
Image.network(
headerImageUrl.isNotEmpty ? headerImageUrl : 'https://via.placeholder.com/800x400',
fit: BoxFit.cover,
),
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.black.withOpacity(0.5),
Colors.transparent,
Colors.transparent,
Colors.black.withOpacity(0.5),
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
),
],
);
},
),
),
),
SliverToBoxAdapter(
child: Container(
padding: EdgeInsets.all(8.0),
color: Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Shared With:',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
Row(
children: [
CircleAvatar(backgroundColor: Colors.blue, child: Text('A')),
SizedBox(width: 8),
CircleAvatar(backgroundColor: Colors.red, child: Text('B')),
SizedBox(width: 8),
CircleAvatar(backgroundColor: Colors.green, child: Text('C')),
// Add more circles as needed
],
),
],
),
),
),
SliverPersistentHeader(
delegate: _SliverAppBarDelegate(
TabBar(
controller: _tabController,
labelColor: Colors.black,
unselectedLabelColor: Colors.grey,
indicatorColor: Colors.black,
indicatorWeight: 2.0,
indicatorSize: TabBarIndicatorSize.label,
tabs: [
Tab(text: 'Notes'),
Tab(text: 'Photos'),
Tab(text: 'Videos'),
],
),
),
pinned: true,
),
];
},
body: TabBarView(
controller: _tabController,
children: [
quill.QuillEditor.basic(
controller: _quillController,
),
StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('images').orderBy('timestamp', descending: true).snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
List<QueryDocumentSnapshot> imagesDocs = snapshot.data!.docs;
return Padding(
padding: const EdgeInsets.all(8.0),
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 1 / 1,
crossAxisSpacing: 8.0,
mainAxisSpacing: 8.0,
),
itemCount: imagesDocs.length + 1,
itemBuilder: (context, index) {
if (index == 0) {
return GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
builder: (context) {
return SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.photo_camera),
title: Text('Take a Photo'),
onTap: () {
Navigator.pop(context);
getImage(ImageSource.camera);
},
),
ListTile(
leading: Icon(Icons.photo_library),
title: Text('Choose from Library'),
onTap: () {
Navigator.pop(context);
getImage(ImageSource.gallery);
},
),
],
),
);
},
);
},
child: Container(
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(8.0),
),
child: Icon(Icons.add, size: 50),
),
);
}
Map<String, dynamic> data = imagesDocs[index - 1].data() as Map<String, dynamic>;
String imageUrl = data['imageUrl'];
String date = data['date'];
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ImageViewPage(
imageUrl: imageUrl,
date: date,
time: date,
),
),
);
},
child: Stack(
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
image: DecorationImage(
image: NetworkImage(imageUrl),
fit: BoxFit.cover,
),
),
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
color: Colors.black54,
padding: EdgeInsets.symmetric(vertical: 2.0),
child: Text(
date,
style: TextStyle(color: Colors.white, fontSize: 12),
),
),
),
),
Positioned(
top: -10,
right: -10,
child: IconButton(
icon: Icon(Icons.delete, color: Colors.red),
onPressed: () {
// Call your delete function here
_deleteImage(imagesDocs[index - 1].id, imageUrl);
},
),
),
],
),
);
},
),
);
},
),
StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('videos').orderBy('timestamp', descending: true).snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
List<QueryDocumentSnapshot> videosDocs = snapshot.data!.docs;
return Padding(
padding: const EdgeInsets.all(8.0),
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 1 / 1,
crossAxisSpacing: 8.0,
mainAxisSpacing: 8.0,
),
itemCount: videosDocs.length + 1,
itemBuilder: (context, index) {
if (index == 0) {
return GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
builder: (context) {
return SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.videocam),
title: Text('Record Video'),
onTap: () {
Navigator.pop(context);
getVideo(ImageSource.camera);
},
),
ListTile(
leading: Icon(Icons.video_library),
title: Text('Choose from Library'),
onTap: () {
Navigator.pop(context);
getVideo(ImageSource.gallery);
},
),
],
),
);
},
);
},
child: Container(
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(8.0),
),
child: Icon(Icons.add, size: 50),
),
);
}
//// Rest of the Code