mirror of
https://github.com/mdanics/fluttergram.git
synced 2025-08-06 13:19:53 +08:00

If you don't do that, many devices won't show image thumbnail after taking picture with the native camera using rear view (because resolution / size is too big). https://dustinstout.com/instagram-sizes/ "For Instagram landscape images, the smallest I have tested on was at 1920×1080 which Instagram then displayed at 600×337. As it turns out, though, Instagram ended up storing a version that is 1080×607." "Vertical images (or portrait) will display at a maximum of 480×600 (or 960×1200 for retina display). However it looks like Instagram is storing the photos at a maximum of 1080×1350 on its servers."
322 lines
9.8 KiB
Dart
322 lines
9.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:image_picker/image_picker.dart';
|
|
import 'package:firebase_storage/firebase_storage.dart';
|
|
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
import 'package:uuid/uuid.dart';
|
|
import 'dart:async';
|
|
import 'main.dart';
|
|
import 'dart:io';
|
|
import 'package:image/image.dart' as Im;
|
|
import 'package:path_provider/path_provider.dart';
|
|
import 'dart:math' as Math;
|
|
import 'location.dart';
|
|
import 'package:geocoder/geocoder.dart';
|
|
|
|
class Uploader extends StatefulWidget {
|
|
_Uploader createState() => new _Uploader();
|
|
}
|
|
|
|
class _Uploader extends State<Uploader> {
|
|
File file;
|
|
//Strings required to save address
|
|
Address address;
|
|
|
|
Map<String, double> currentLocation = new Map();
|
|
TextEditingController descriptionController = new TextEditingController();
|
|
TextEditingController locationController = new TextEditingController();
|
|
|
|
bool uploading = false;
|
|
bool promted = false;
|
|
|
|
@override
|
|
initState() {
|
|
if (file == null && promted == false && pageController.page == 2) {
|
|
_selectImage();
|
|
setState(() {
|
|
promted = true;
|
|
});
|
|
}
|
|
//variables with location assigned as 0.0
|
|
currentLocation['latitude'] = 0.0;
|
|
currentLocation['longitude'] = 0.0;
|
|
initPlatformState(); //method to call location
|
|
super.initState();
|
|
}
|
|
|
|
//method to get Location and save into variables
|
|
initPlatformState() async {
|
|
Address first = await getUserLocation();
|
|
setState(() {
|
|
address = first;
|
|
});
|
|
}
|
|
|
|
Widget build(BuildContext context) {
|
|
return file == null
|
|
? new IconButton(
|
|
icon: new Icon(Icons.file_upload), onPressed: _selectImage)
|
|
: new Scaffold(
|
|
resizeToAvoidBottomPadding: false,
|
|
appBar: new AppBar(
|
|
backgroundColor: Colors.white70,
|
|
leading: new IconButton(
|
|
icon: new Icon(Icons.arrow_back, color: Colors.black),
|
|
onPressed: clearImage),
|
|
title: const Text(
|
|
'Post to',
|
|
style: const TextStyle(color: Colors.black),
|
|
),
|
|
actions: <Widget>[
|
|
new FlatButton(
|
|
onPressed: postImage,
|
|
child: new Text(
|
|
"Post",
|
|
style: new TextStyle(
|
|
color: Colors.blueAccent,
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 20.0),
|
|
))
|
|
],
|
|
),
|
|
body: new ListView(
|
|
children: <Widget>[
|
|
new PostForm(
|
|
imageFile: file,
|
|
descriptionController: descriptionController,
|
|
locationController: locationController,
|
|
loading: uploading,
|
|
),
|
|
new Divider(), //scroll view where we will show location to users
|
|
(address == null)
|
|
? Container()
|
|
: new SingleChildScrollView(
|
|
scrollDirection: Axis.horizontal,
|
|
padding: EdgeInsets.only(right: 5.0, left: 5.0),
|
|
child: Row(
|
|
children: <Widget>[
|
|
buildLocationButton(address.featureName),
|
|
buildLocationButton(address.subLocality),
|
|
buildLocationButton(address.locality),
|
|
buildLocationButton(address.subAdminArea),
|
|
buildLocationButton(address.adminArea),
|
|
buildLocationButton(address.countryName),
|
|
],
|
|
),
|
|
),
|
|
(address == null) ? Container() : Divider(),
|
|
],
|
|
));
|
|
}
|
|
|
|
//method to build buttons with location.
|
|
buildLocationButton(String locationName) {
|
|
if (locationName != null ?? locationName.isNotEmpty) {
|
|
return InkWell(
|
|
onTap: () {
|
|
locationController.text = locationName;
|
|
},
|
|
child: Center(
|
|
child: new Container(
|
|
//width: 100.0,
|
|
height: 30.0,
|
|
padding: EdgeInsets.only(left: 8.0, right: 8.0),
|
|
margin: EdgeInsets.only(right: 3.0, left: 3.0),
|
|
decoration: new BoxDecoration(
|
|
color: Colors.grey[200],
|
|
borderRadius: new BorderRadius.circular(5.0),
|
|
),
|
|
child: new Center(
|
|
child: new Text(
|
|
locationName,
|
|
style: new TextStyle(color: Colors.grey),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
} else {
|
|
return Container();
|
|
}
|
|
}
|
|
|
|
_selectImage() async {
|
|
return showDialog<Null>(
|
|
context: context,
|
|
barrierDismissible: false, // user must tap button!
|
|
|
|
builder: (BuildContext context) {
|
|
return new SimpleDialog(
|
|
title: const Text('Create a Post'),
|
|
children: <Widget>[
|
|
new SimpleDialogOption(
|
|
child: const Text('Take a photo'),
|
|
onPressed: () async {
|
|
Navigator.pop(context);
|
|
File imageFile =
|
|
await ImagePicker.pickImage(source: ImageSource.camera, maxWidth: 1920, maxHeight: 1350);
|
|
setState(() {
|
|
file = imageFile;
|
|
});
|
|
}),
|
|
new SimpleDialogOption(
|
|
child: const Text('Choose from Gallery'),
|
|
onPressed: () async {
|
|
Navigator.of(context).pop();
|
|
File imageFile =
|
|
await ImagePicker.pickImage(source: ImageSource.gallery);
|
|
setState(() {
|
|
file = imageFile;
|
|
});
|
|
}),
|
|
new SimpleDialogOption(
|
|
child: const Text("Cancel"),
|
|
onPressed: () {
|
|
Navigator.pop(context);
|
|
},
|
|
)
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
void compressImage() async {
|
|
print('starting compression');
|
|
final tempDir = await getTemporaryDirectory();
|
|
final path = tempDir.path;
|
|
int rand = new Math.Random().nextInt(10000);
|
|
|
|
Im.Image image = Im.decodeImage(file.readAsBytesSync());
|
|
Im.copyResize(image, 500);
|
|
|
|
// image.format = Im.Image.RGBA;
|
|
// Im.Image newim = Im.remapColors(image, alpha: Im.LUMINANCE);
|
|
|
|
var newim2 = new File('$path/img_$rand.jpg')
|
|
..writeAsBytesSync(Im.encodeJpg(image, quality: 85));
|
|
|
|
setState(() {
|
|
file = newim2;
|
|
});
|
|
print('done');
|
|
}
|
|
|
|
void clearImage() {
|
|
setState(() {
|
|
file = null;
|
|
});
|
|
}
|
|
|
|
void postImage() {
|
|
setState(() {
|
|
uploading = true;
|
|
});
|
|
compressImage();
|
|
uploadImage(file).then((String data) {
|
|
postToFireStore(
|
|
mediaUrl: data,
|
|
description: descriptionController.text,
|
|
location: locationController.text);
|
|
}).then((_) {
|
|
setState(() {
|
|
file = null;
|
|
uploading = false;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
class PostForm extends StatelessWidget {
|
|
final imageFile;
|
|
final TextEditingController descriptionController;
|
|
final TextEditingController locationController;
|
|
final bool loading;
|
|
PostForm(
|
|
{this.imageFile,
|
|
this.descriptionController,
|
|
this.loading,
|
|
this.locationController});
|
|
|
|
Widget build(BuildContext context) {
|
|
return new Column(
|
|
children: <Widget>[
|
|
loading
|
|
? new LinearProgressIndicator()
|
|
: new Padding(padding: new EdgeInsets.only(top: 0.0)),
|
|
new Divider(),
|
|
new Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: <Widget>[
|
|
new CircleAvatar(
|
|
backgroundImage: new NetworkImage(currentUserModel.photoUrl),
|
|
),
|
|
new Container(
|
|
width: 250.0,
|
|
child: new TextField(
|
|
controller: descriptionController,
|
|
decoration: new InputDecoration(
|
|
hintText: "Write a caption...", border: InputBorder.none),
|
|
),
|
|
),
|
|
new Container(
|
|
height: 45.0,
|
|
width: 45.0,
|
|
child: new AspectRatio(
|
|
aspectRatio: 487 / 451,
|
|
child: new Container(
|
|
decoration: new BoxDecoration(
|
|
image: new DecorationImage(
|
|
fit: BoxFit.fill,
|
|
alignment: FractionalOffset.topCenter,
|
|
image: new FileImage(imageFile),
|
|
)),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
new Divider(),
|
|
new ListTile(
|
|
leading: new Icon(Icons.pin_drop),
|
|
title: new Container(
|
|
width: 250.0,
|
|
child: new TextField(
|
|
controller: locationController,
|
|
decoration: new InputDecoration(
|
|
hintText: "Where was this photo taken?",
|
|
border: InputBorder.none),
|
|
),
|
|
),
|
|
)
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<String> uploadImage(var imageFile) async {
|
|
var uuid = new Uuid().v1();
|
|
StorageReference ref = FirebaseStorage.instance.ref().child("post_$uuid.jpg");
|
|
StorageUploadTask uploadTask = ref.putFile(imageFile);
|
|
|
|
String downloadUrl = await (await uploadTask.onComplete).ref.getDownloadURL();
|
|
return downloadUrl;
|
|
}
|
|
|
|
void postToFireStore(
|
|
{String mediaUrl, String location, String description}) async {
|
|
var reference = Firestore.instance.collection('insta_posts');
|
|
|
|
reference.add({
|
|
"username": currentUserModel.username,
|
|
"location": location,
|
|
"likes": {},
|
|
"mediaUrl": mediaUrl,
|
|
"description": description,
|
|
"ownerId": googleSignIn.currentUser.id,
|
|
"timestamp": new DateTime.now().toString(),
|
|
}).then((DocumentReference doc) {
|
|
String docId = doc.documentID;
|
|
reference.document(docId).updateData({"postId": docId});
|
|
});
|
|
}
|