Skip to content
Snippets Groups Projects
Commit b1ce13e3 authored by Michal Cikatricis's avatar Michal Cikatricis
Browse files

Merge branch 'master' of https://gitlab.fi.muni.cz/stamped_dev/stamped into home_page

parents 7be462f2 14561293
No related branches found
No related tags found
1 merge request!37Save postcards
...@@ -26,6 +26,10 @@ ...@@ -26,6 +26,10 @@
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
<!-- Don't delete the meta-data below. <!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data <meta-data
......
...@@ -47,5 +47,11 @@ ...@@ -47,5 +47,11 @@
<true/> <true/>
<key>UIApplicationSupportsIndirectInputEvents</key> <key>UIApplicationSupportsIndirectInputEvents</key>
<true/> <true/>
<key>NSPhotoLibraryUsageDescription</key>
<string>Need to upload image</string>
<key>NSCameraUsageDescription</key>
<string>Need to upload image</string>
<key>NSMicrophoneUsageDescription</key>
<string>Need to upload image</string>
</dict> </dict>
</plist> </plist>
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:stamped/bottom_nav_bar/model/bottom_nav_bar_item.dart'; import 'package:stamped/bottom_nav_bar/model/bottom_nav_bar_item.dart';
import 'package:stamped/pages/collections/collections_page.dart'; import 'package:stamped/pages/collections/collections_page.dart';
import 'package:stamped/pages/create_front/notifiers/create_postcard_notifier.dart';
import 'package:stamped/pages/create_front/select_image.dart';
import 'package:stamped/pages/home/home_page.dart'; import 'package:stamped/pages/home/home_page.dart';
import 'package:stamped/pages/profile/profile_page.dart'; import 'package:stamped/pages/profile/profile_page.dart';
...@@ -19,7 +22,7 @@ final List<BottomNavBarItem> _navItems = [ ...@@ -19,7 +22,7 @@ final List<BottomNavBarItem> _navItems = [
label: 'Create', label: 'Create',
icon: Icon(Icons.add), icon: Icon(Icons.add),
// TODO: replace with the create page // TODO: replace with the create page
child: Placeholder(), child: SelectImage(),
), ),
BottomNavBarItem( BottomNavBarItem(
label: 'Friends', label: 'Friends',
...@@ -46,24 +49,27 @@ class _BottomNavBarState extends State<BottomNavBar> { ...@@ -46,24 +49,27 @@ class _BottomNavBarState extends State<BottomNavBar> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return ChangeNotifierProvider(
body: _navItems[_currentIndex].child, create: (context) => CreatePostcardNotifier(),
bottomNavigationBar: BottomNavigationBar( child: Scaffold(
currentIndex: _currentIndex, body: _navItems[_currentIndex].child,
items: _navItems bottomNavigationBar: BottomNavigationBar(
.map( currentIndex: _currentIndex,
(item) => BottomNavigationBarItem( items: _navItems
label: item.label, .map(
icon: item.icon, (item) => BottomNavigationBarItem(
), label: item.label,
) icon: item.icon,
.toList(), ),
onTap: _onItemTap, )
type: BottomNavigationBarType.fixed, .toList(),
selectedItemColor: Colors.black87, onTap: _onItemTap,
unselectedItemColor: Colors.grey[400], type: BottomNavigationBarType.fixed,
showSelectedLabels: false, selectedItemColor: Colors.black87,
showUnselectedLabels: false, unselectedItemColor: Colors.grey[400],
showSelectedLabels: false,
showUnselectedLabels: false,
),
), ),
); );
} }
......
enum ImageType {
postcard,
stamp,
}
...@@ -62,16 +62,18 @@ class PostcardTile extends StatelessWidget { ...@@ -62,16 +62,18 @@ class PostcardTile extends StatelessWidget {
Widget _senderDetail(MediaService mediaService) { Widget _senderDetail(MediaService mediaService) {
return Row( return Row(
children: [ children: [
Text(postcard.sender.userName.length > 14 Text(
? '${postcard.sender.userName.substring(0, 14)}..' postcard.sender.userName,
: postcard.sender.userName), overflow: TextOverflow.fade,
),
Spacer(), Spacer(),
FutureBuilderHandler( FutureBuilderHandler(
future: mediaService.getFlagBitcode(postcard.originLocation), future: mediaService.getFlagBitcode(postcard.originLocation),
builder: (BuildContext context, data) { builder: (BuildContext context, data) {
return Text( return Text(
data, data,
style: TextStyle(fontSize: 25), style: TextStyle(
fontSize: MediaQuery.of(context).textScaleFactor * 20),
); );
}, },
), ),
......
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:stamped/common/service/ioc_container.dart';
import 'package:stamped/data/enums/image_type.dart';
import 'package:stamped/service/media_service.dart';
import 'package:image_cropper/image_cropper.dart';
class CreatePostcardNotifier extends ChangeNotifier {
File? _postcardImage;
String _postcardImageDownloadUrl = '';
final _mediaService = get<MediaService>();
File? get selectedImage => _postcardImage;
Future<void> pickImage(ImageSource source) async {
final pickedFile = await ImagePicker().pickImage(source: source);
if (pickedFile != null) {
_postcardImage = File(pickedFile.path);
notifyListeners();
}
final croppedFile = await cropImage();
if (croppedFile != null) {
_postcardImage = File(croppedFile.path);
notifyListeners();
}
}
Future<CroppedFile?> cropImage() async {
CroppedFile? croppedFile = await ImageCropper().cropImage(
sourcePath: _postcardImage!.path,
uiSettings: [
AndroidUiSettings(
toolbarTitle: 'Crop Image',
toolbarColor: Colors.white,
initAspectRatio: CropAspectRatioPreset.square,
lockAspectRatio: true,
hideBottomControls: true,
backgroundColor: Colors.white,
activeControlsWidgetColor: Colors.grey,
),
IOSUiSettings(
title: 'Cropper',
),
],
);
return croppedFile;
}
Future<void> uploadPostcardImage() async {
final imageRef = await _mediaService.uploadImage(
_postcardImage!,
imageType: ImageType.postcard,
);
if (imageRef == null) {
_postcardImageDownloadUrl = '';
return;
}
_postcardImageDownloadUrl = await imageRef.getDownloadURL();
}
}
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:provider/provider.dart';
import 'package:stamped/common/widget/page_template.dart';
import 'package:stamped/pages/create_front/notifiers/create_postcard_notifier.dart';
class SelectImage extends StatelessWidget {
const SelectImage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final createPostcardNotifier = context.watch<CreatePostcardNotifier>();
return PageTemplate(
title: 'Create a Postcard',
actions: [
IconButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
// TODO: use create postcard back page
builder: (context) => PageTemplate(
title: 'Create a Postcard',
child: Placeholder(),
),
),
);
},
icon: Icon(Icons.navigate_next),
),
],
child: Align(
alignment: Alignment.bottomCenter,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Spacer(),
createPostcardNotifier.selectedImage == null
? Text('No Image Selected')
: Image.file(
createPostcardNotifier.selectedImage!,
width: double.infinity,
),
Spacer(),
_buildPickImageButton(
createPostcardNotifier,
source: ImageSource.gallery,
),
_buildPickImageButton(
createPostcardNotifier,
source: ImageSource.camera,
),
],
),
),
);
}
ElevatedButton _buildPickImageButton(
CreatePostcardNotifier createPostcardNotifier, {
required ImageSource source,
}) {
return ElevatedButton.icon(
onPressed: () => createPostcardNotifier.pickImage(source),
icon: Icon(Icons.photo_library),
label: Text(source == ImageSource.gallery
? 'Pick Image from Gallery'
: 'Take Image from Camera'),
);
}
}
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:path/path.dart' as p;
import 'package:stamped/data/entities/country_entity.dart'; import 'package:stamped/data/entities/country_entity.dart';
import 'package:stamped/data/enums/image_type.dart';
class MediaService { class MediaService {
final _postcardImagesRef =
FirebaseStorage.instance.ref().child('postcardImages');
final _stampsRef = FirebaseStorage.instance.ref().child('stamps');
final _countryCollection = final _countryCollection =
FirebaseFirestore.instance.collection('countries').withConverter( FirebaseFirestore.instance.collection('countries').withConverter(
fromFirestore: (snapshot, options) { fromFirestore: (snapshot, options) {
...@@ -24,8 +33,26 @@ class MediaService { ...@@ -24,8 +33,26 @@ class MediaService {
return countrySnapshot.data()!.flag; return countrySnapshot.data()!.flag;
} }
Future<void> uploadImage() async { Future<Reference?> uploadImage(
//TODO File file, {
required ImageType imageType,
}) async {
final storageRef =
imageType == ImageType.postcard ? _postcardImagesRef : _stampsRef;
final fileName = _genUniqueFileName(file);
final uploadTask = await storageRef.child(fileName).putFile(file);
if (uploadTask.state != TaskState.success) {
return null;
}
return storageRef.child(fileName);
}
String _genUniqueFileName(File file) {
final time = DateTime.now().millisecondsSinceEpoch.toString();
return '$time${p.basename(file.path)}';
} }
Future<void> deleteImage() async { Future<void> deleteImage() async {
......
...@@ -209,6 +209,14 @@ packages: ...@@ -209,6 +209,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.1" version: "3.1.1"
cross_file:
dependency: transitive
description:
name: cross_file
sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9"
url: "https://pub.dev"
source: hosted
version: "0.3.3+4"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
...@@ -366,6 +374,14 @@ packages: ...@@ -366,6 +374,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "2.0.1"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: "950e77c2bbe1692bc0874fc7fb491b96a4dc340457f4ea1641443d0a6c1ea360"
url: "https://pub.dev"
source: hosted
version: "2.0.15"
flutter_signin_button: flutter_signin_button:
dependency: "direct main" dependency: "direct main"
description: description:
...@@ -576,6 +592,70 @@ packages: ...@@ -576,6 +592,70 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.2" version: "4.0.2"
image_cropper:
dependency: "direct main"
description:
name: image_cropper
sha256: "542c3453109d16bcc388e43ae2276044d2cd6a6d20c68bdcff2c94ab9363ea15"
url: "https://pub.dev"
source: hosted
version: "4.0.1"
image_cropper_for_web:
dependency: transitive
description:
name: image_cropper_for_web
sha256: "89c936aa772a35b69ca67b78049ae9fa163a4fb8da2f6dee3893db8883fb49d2"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
image_cropper_platform_interface:
dependency: transitive
description:
name: image_cropper_platform_interface
sha256: b232175c132b2f7ede3e1f101652bcd635cb4079a77c6dded8e6d32e6578d685
url: "https://pub.dev"
source: hosted
version: "4.0.0"
image_picker:
dependency: "direct main"
description:
name: image_picker
sha256: "9978d3510af4e6a902e545ce19229b926e6de6a1828d6134d3aab2e129a4d270"
url: "https://pub.dev"
source: hosted
version: "0.8.7+5"
image_picker_android:
dependency: transitive
description:
name: image_picker_android
sha256: c2f3c66400649bd132f721c88218945d6406f693092b2f741b79ae9cdb046e59
url: "https://pub.dev"
source: hosted
version: "0.8.6+16"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
sha256: "98f50d6b9f294c8ba35e25cc0d13b04bfddd25dbc8d32fa9d566a6572f2c081c"
url: "https://pub.dev"
source: hosted
version: "2.1.12"
image_picker_ios:
dependency: transitive
description:
name: image_picker_ios
sha256: d779210bda268a03b57e923fb1e410f32f5c5e708ad256348bcbf1f44f558fd0
url: "https://pub.dev"
source: hosted
version: "0.8.7+4"
image_picker_platform_interface:
dependency: transitive
description:
name: image_picker_platform_interface
sha256: "1991219d9dbc42a99aff77e663af8ca51ced592cd6685c9485e3458302d3d4f8"
url: "https://pub.dev"
source: hosted
version: "2.6.3"
intl: intl:
dependency: transitive dependency: transitive
description: description:
...@@ -689,7 +769,7 @@ packages: ...@@ -689,7 +769,7 @@ packages:
source: hosted source: hosted
version: "2.1.0" version: "2.1.0"
path: path:
dependency: transitive dependency: "direct main"
description: description:
name: path name: path
sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b
......
...@@ -47,6 +47,9 @@ dependencies: ...@@ -47,6 +47,9 @@ dependencies:
firebase_storage: ^11.1.2 firebase_storage: ^11.1.2
provider: ^6.0.5 provider: ^6.0.5
cached_network_image: ^3.2.3 cached_network_image: ^3.2.3
image_picker: ^0.8.7+5
path: ^1.8.2
image_cropper: ^4.0.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment