overall bug fixes + UI changes
This commit is contained in:
parent
2275b582b4
commit
4f5ba12f2d
@ -6,7 +6,7 @@ class Animator extends StatefulWidget {
|
|||||||
final Widget child;
|
final Widget child;
|
||||||
final Duration time;
|
final Duration time;
|
||||||
|
|
||||||
const Animator(this.child, this.time, {Key? key}) : super(key: key);
|
const Animator(this.child, this.time, {Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_AnimatorState createState() => _AnimatorState();
|
_AnimatorState createState() => _AnimatorState();
|
||||||
@ -14,9 +14,9 @@ class Animator extends StatefulWidget {
|
|||||||
|
|
||||||
class _AnimatorState extends State<Animator>
|
class _AnimatorState extends State<Animator>
|
||||||
with SingleTickerProviderStateMixin {
|
with SingleTickerProviderStateMixin {
|
||||||
Timer? timer;
|
Timer timer;
|
||||||
AnimationController? animationController;
|
AnimationController animationController;
|
||||||
Animation? animation;
|
Animation animation;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -24,27 +24,27 @@ class _AnimatorState extends State<Animator>
|
|||||||
animationController = AnimationController(
|
animationController = AnimationController(
|
||||||
duration: const Duration(milliseconds: 290), vsync: this);
|
duration: const Duration(milliseconds: 290), vsync: this);
|
||||||
animation =
|
animation =
|
||||||
CurvedAnimation(parent: animationController!, curve: Curves.easeInOut);
|
CurvedAnimation(parent: animationController, curve: Curves.easeInOut);
|
||||||
timer = Timer(widget.time, animationController!.forward);
|
timer = Timer(widget.time, animationController.forward);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
animationController!.dispose();
|
animationController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
timer!.cancel();
|
timer.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AnimatedBuilder(
|
return AnimatedBuilder(
|
||||||
animation: animation!,
|
animation: animation,
|
||||||
child: widget.child,
|
child: widget.child,
|
||||||
builder: (BuildContext context, Widget? child) {
|
builder: (BuildContext context, Widget child) {
|
||||||
return Opacity(
|
return Opacity(
|
||||||
opacity: animation!.value,
|
opacity: animation.value,
|
||||||
child: Transform.translate(
|
child: Transform.translate(
|
||||||
offset: Offset(0.0, (1 - animation!.value) * 20),
|
offset: Offset(0.0, (1 - animation.value) * 20),
|
||||||
child: child,
|
child: child,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -53,11 +53,11 @@ class _AnimatorState extends State<Animator>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer? timer;
|
Timer timer;
|
||||||
Duration duration = const Duration();
|
Duration duration = const Duration();
|
||||||
|
|
||||||
Duration wait() {
|
Duration wait() {
|
||||||
if (timer == null || !timer!.isActive) {
|
if (timer == null || !timer.isActive) {
|
||||||
timer = Timer(const Duration(microseconds: 120), () {
|
timer = Timer(const Duration(microseconds: 120), () {
|
||||||
duration = const Duration();
|
duration = const Duration();
|
||||||
});
|
});
|
||||||
@ -67,12 +67,12 @@ Duration wait() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class WidgetAnimator extends StatelessWidget {
|
class WidgetAnimator extends StatelessWidget {
|
||||||
final Widget? child;
|
final Widget child;
|
||||||
|
|
||||||
const WidgetAnimator({this.child, Key? key}) : super(key: key);
|
const WidgetAnimator({this.child, Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Animator(child!, wait());
|
return Animator(child, wait());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
class EntranceFader extends StatefulWidget {
|
class EntranceFader extends StatefulWidget {
|
||||||
/// Child to be animated on entrance
|
/// Child to be animated on entrance
|
||||||
final Widget? child;
|
final Widget child;
|
||||||
|
|
||||||
/// Delay after which the animation will start
|
/// Delay after which the animation will start
|
||||||
final Duration delay;
|
final Duration delay;
|
||||||
@ -14,7 +14,7 @@ class EntranceFader extends StatefulWidget {
|
|||||||
final Offset offset;
|
final Offset offset;
|
||||||
|
|
||||||
const EntranceFader({
|
const EntranceFader({
|
||||||
Key? key,
|
Key key,
|
||||||
this.child,
|
this.child,
|
||||||
this.delay = const Duration(milliseconds: 0),
|
this.delay = const Duration(milliseconds: 0),
|
||||||
this.duration = const Duration(milliseconds: 400),
|
this.duration = const Duration(milliseconds: 400),
|
||||||
@ -29,39 +29,39 @@ class EntranceFader extends StatefulWidget {
|
|||||||
|
|
||||||
class EntranceFaderState extends State<EntranceFader>
|
class EntranceFaderState extends State<EntranceFader>
|
||||||
with SingleTickerProviderStateMixin {
|
with SingleTickerProviderStateMixin {
|
||||||
AnimationController? _controller;
|
AnimationController _controller;
|
||||||
Animation? _dxAnimation;
|
Animation _dxAnimation;
|
||||||
Animation? _dyAnimation;
|
Animation _dyAnimation;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_controller = AnimationController(vsync: this, duration: widget.duration);
|
_controller = AnimationController(vsync: this, duration: widget.duration);
|
||||||
_dxAnimation =
|
_dxAnimation =
|
||||||
Tween(begin: widget.offset.dx, end: 0.0).animate(_controller!);
|
Tween(begin: widget.offset.dx, end: 0.0).animate(_controller);
|
||||||
_dyAnimation =
|
_dyAnimation =
|
||||||
Tween(begin: widget.offset.dy, end: 0.0).animate(_controller!);
|
Tween(begin: widget.offset.dy, end: 0.0).animate(_controller);
|
||||||
Future.delayed(widget.delay, () {
|
Future.delayed(widget.delay, () {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
_controller!.forward();
|
_controller.forward();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_controller!.dispose();
|
_controller.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AnimatedBuilder(
|
return AnimatedBuilder(
|
||||||
animation: _controller!,
|
animation: _controller,
|
||||||
builder: (context, child) => Opacity(
|
builder: (context, child) => Opacity(
|
||||||
opacity: _controller!.value,
|
opacity: _controller.value,
|
||||||
child: Transform.translate(
|
child: Transform.translate(
|
||||||
offset: Offset(_dxAnimation!.value, _dyAnimation!.value),
|
offset: Offset(_dxAnimation.value, _dyAnimation.value),
|
||||||
child: widget.child,
|
child: widget.child,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -14,5 +14,6 @@ class ScrollBehaviorModified extends ScrollBehavior {
|
|||||||
case TargetPlatform.windows:
|
case TargetPlatform.windows:
|
||||||
return const ClampingScrollPhysics();
|
return const ClampingScrollPhysics();
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const MyApp({Key? key}) : super(key: key);
|
const MyApp({Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -38,9 +38,7 @@ class MyApp extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
builder: (context, widget) {
|
builder: (context, widget) {
|
||||||
return ScrollConfiguration(
|
return ScrollConfiguration(
|
||||||
behavior: const ScrollBehaviorModified(),
|
behavior: const ScrollBehaviorModified(), child: widget);
|
||||||
child: widget!,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
initialRoute: AppRoutes.splash,
|
initialRoute: AppRoutes.splash,
|
||||||
routes: <String, WidgetBuilder>{
|
routes: <String, WidgetBuilder>{
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class Contact {
|
class Contact {
|
||||||
final String? name;
|
final String name;
|
||||||
final String? msg;
|
final String msg;
|
||||||
final String? msgTime;
|
final String msgTime;
|
||||||
|
|
||||||
Contact({this.name, this.msg, this.msgTime});
|
Contact({this.name, this.msg, this.msgTime});
|
||||||
|
|
||||||
@ -26,8 +26,8 @@ class Contact {
|
|||||||
.toList(),
|
.toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
static List<Contact> decode(String? contacts) =>
|
static List<Contact> decode(String contacts) =>
|
||||||
(json.decode(contacts!) as List<dynamic>)
|
(json.decode(contacts) as List<dynamic>)
|
||||||
.map<Contact>((item) => Contact.fromJson(item))
|
.map<Contact>((item) => Contact.fromJson(item))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class Group {
|
class Group {
|
||||||
final String? groupName;
|
final String photoPath;
|
||||||
final String? groupDescription;
|
final String groupName;
|
||||||
|
final String groupDescription;
|
||||||
final List<dynamic> members;
|
final List<dynamic> members;
|
||||||
|
|
||||||
Group({this.groupName, this.groupDescription, this.members = const []});
|
Group(
|
||||||
|
{this.groupName,
|
||||||
|
this.photoPath,
|
||||||
|
this.groupDescription,
|
||||||
|
this.members = const []});
|
||||||
|
|
||||||
factory Group.fromJson(Map<String, dynamic> json) {
|
factory Group.fromJson(Map<String, dynamic> json) {
|
||||||
return Group(
|
return Group(
|
||||||
|
photoPath: json['gPhoto'],
|
||||||
groupName: json['gName'],
|
groupName: json['gName'],
|
||||||
groupDescription: json['desc'],
|
groupDescription: json['desc'],
|
||||||
members: json['contacts'],
|
members: json['contacts'],
|
||||||
@ -17,6 +23,7 @@ class Group {
|
|||||||
|
|
||||||
static Map<String, dynamic> toJson(Group group) {
|
static Map<String, dynamic> toJson(Group group) {
|
||||||
return {
|
return {
|
||||||
|
'gPhoto': group.photoPath,
|
||||||
'gName': group.groupName,
|
'gName': group.groupName,
|
||||||
'desc': group.groupDescription,
|
'desc': group.groupDescription,
|
||||||
'contacts': group.members,
|
'contacts': group.members,
|
||||||
@ -29,8 +36,8 @@ class Group {
|
|||||||
.toList(),
|
.toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
static List<Group> decode(String? groups) =>
|
static List<Group> decode(String groups) =>
|
||||||
(json.decode(groups!) as List<dynamic>)
|
(json.decode(groups) as List<dynamic>)
|
||||||
.map<Group>((item) => Group.fromJson(item))
|
.map<Group>((item) => Group.fromJson(item))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
class DrawerProvider extends ChangeNotifier {
|
class DrawerProvider extends ChangeNotifier {
|
||||||
int _currentIndex = 0;
|
int _currentIndex = 1;
|
||||||
|
|
||||||
int get currentIndex => _currentIndex;
|
int get currentIndex => _currentIndex;
|
||||||
|
|
||||||
@ -9,13 +9,4 @@ class DrawerProvider extends ChangeNotifier {
|
|||||||
_currentIndex = value;
|
_currentIndex = value;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
// toggle drawer
|
|
||||||
TickerFuture toggle(
|
|
||||||
AnimationController? animationController) {
|
|
||||||
|
|
||||||
return animationController!.isDismissed
|
|
||||||
? animationController.forward()
|
|
||||||
: animationController.reverse();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import 'package:qr_code_scanner/qr_code_scanner.dart';
|
|||||||
import 'package:simplex_chat/views/contacts/qr_code_details_view.dart';
|
import 'package:simplex_chat/views/contacts/qr_code_details_view.dart';
|
||||||
|
|
||||||
class AddContactView extends StatefulWidget {
|
class AddContactView extends StatefulWidget {
|
||||||
const AddContactView({Key? key}) : super(key: key);
|
const AddContactView({Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_AddContactViewState createState() => _AddContactViewState();
|
_AddContactViewState createState() => _AddContactViewState();
|
||||||
@ -13,16 +13,16 @@ class AddContactView extends StatefulWidget {
|
|||||||
|
|
||||||
class _AddContactViewState extends State<AddContactView> {
|
class _AddContactViewState extends State<AddContactView> {
|
||||||
final qrKey = GlobalKey(debugLabel: 'qr');
|
final qrKey = GlobalKey(debugLabel: 'qr');
|
||||||
QRViewController? _qrViewController;
|
QRViewController _qrViewController;
|
||||||
Barcode? result;
|
Barcode result;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void reassemble() {
|
void reassemble() {
|
||||||
super.reassemble();
|
super.reassemble();
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
_qrViewController!.pauseCamera();
|
_qrViewController.pauseCamera();
|
||||||
} else if (Platform.isIOS) {
|
} else if (Platform.isIOS) {
|
||||||
_qrViewController!.resumeCamera();
|
_qrViewController.resumeCamera();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,14 +9,14 @@ import 'package:simplex_chat/model/contact.dart';
|
|||||||
import 'package:simplex_chat/views/conversation/conversation_view.dart';
|
import 'package:simplex_chat/views/conversation/conversation_view.dart';
|
||||||
|
|
||||||
class ContactsView extends StatefulWidget {
|
class ContactsView extends StatefulWidget {
|
||||||
const ContactsView({Key? key}) : super(key: key);
|
const ContactsView({Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_ContactsViewState createState() => _ContactsViewState();
|
_ContactsViewState createState() => _ContactsViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ContactsViewState extends State<ContactsView> {
|
class _ContactsViewState extends State<ContactsView> {
|
||||||
bool? _eraseMedia = false;
|
bool _eraseMedia = false;
|
||||||
|
|
||||||
List<Contact> _contactsList = []; // for storing contacts
|
List<Contact> _contactsList = []; // for storing contacts
|
||||||
|
|
||||||
@ -44,14 +44,16 @@ class _ContactsViewState extends State<ContactsView> {
|
|||||||
// getting data from local storage FOR NOW!!
|
// getting data from local storage FOR NOW!!
|
||||||
void _getContacts() async {
|
void _getContacts() async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
final String? _contacts = prefs.getString('contacts');
|
final String _contacts = prefs.getString('contacts');
|
||||||
setState(() {
|
if (_contacts != null) {
|
||||||
_contactsList = List.from(Contact.decode(_contacts));
|
setState(() {
|
||||||
});
|
_contactsList = List.from(Contact.decode(_contacts));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String? _photo;
|
String _photo = '';
|
||||||
String? _displayName;
|
String _displayName = '';
|
||||||
|
|
||||||
void _getUserData() async {
|
void _getUserData() async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
@ -89,10 +91,13 @@ class _ContactsViewState extends State<ContactsView> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10.0),
|
const SizedBox(width: 10.0),
|
||||||
CircleAvatar(
|
GestureDetector(
|
||||||
backgroundImage: _photo == null
|
onTap: _addNewContacts,
|
||||||
? const AssetImage('assets/dp.png') as ImageProvider
|
child: CircleAvatar(
|
||||||
: FileImage(File(_photo!)),
|
backgroundImage: _photo.isEmpty
|
||||||
|
? const AssetImage('assets/dp.png') as ImageProvider
|
||||||
|
: FileImage(File(_photo)),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -138,10 +143,10 @@ class _ContactsViewState extends State<ContactsView> {
|
|||||||
leading: const CircleAvatar(
|
leading: const CircleAvatar(
|
||||||
backgroundImage: AssetImage('assets/dp.png'),
|
backgroundImage: AssetImage('assets/dp.png'),
|
||||||
),
|
),
|
||||||
title: Text(_contactsList[index].name!),
|
title: Text(_contactsList[index].name),
|
||||||
subtitle: Text(_contactsList[index].msg!),
|
subtitle: Text(_contactsList[index].msg),
|
||||||
trailing: Text(
|
trailing: Text(
|
||||||
_contactsList[index].msgTime!,
|
_contactsList[index].msgTime,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 11, color: Colors.grey),
|
fontSize: 11, color: Colors.grey),
|
||||||
),
|
),
|
||||||
@ -171,9 +176,9 @@ class _ContactsViewState extends State<ContactsView> {
|
|||||||
offset: const Offset(-10, -120),
|
offset: const Offset(-10, -120),
|
||||||
onSelected: (value) {
|
onSelected: (value) {
|
||||||
if (value == _options[0]) {
|
if (value == _options[0]) {
|
||||||
Navigator.pushNamed(context, AppRoutes.addContact);
|
|
||||||
} else {
|
|
||||||
Navigator.pushNamed(context, AppRoutes.scanInvitation);
|
Navigator.pushNamed(context, AppRoutes.scanInvitation);
|
||||||
|
} else {
|
||||||
|
Navigator.pushNamed(context, AppRoutes.addContact);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
itemBuilder: (context) => _options
|
itemBuilder: (context) => _options
|
||||||
@ -325,7 +330,10 @@ class _ContactsViewState extends State<ContactsView> {
|
|||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
List<Contact> _localList = [];
|
List<Contact> _localList = [];
|
||||||
_localList = List.from(Contact.decode(prefs.getString('contacts')));
|
final String _local = prefs.getString('contacts');
|
||||||
|
if (_local != null) {
|
||||||
|
_localList = List.from(Contact.decode(_local));
|
||||||
|
}
|
||||||
|
|
||||||
List<Contact> _newList = [
|
List<Contact> _newList = [
|
||||||
Contact(
|
Contact(
|
||||||
|
@ -4,9 +4,9 @@ import 'package:simplex_chat/constants.dart';
|
|||||||
import 'package:simplex_chat/widgets/custom_btn.dart';
|
import 'package:simplex_chat/widgets/custom_btn.dart';
|
||||||
|
|
||||||
class QRCodeDetailsView extends StatelessWidget {
|
class QRCodeDetailsView extends StatelessWidget {
|
||||||
final Barcode? barcode;
|
final Barcode barcode;
|
||||||
const QRCodeDetailsView({
|
const QRCodeDetailsView({
|
||||||
Key? key,
|
Key key,
|
||||||
this.barcode,
|
this.barcode,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ class QRCodeDetailsView extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 30.0),
|
const SizedBox(height: 30.0),
|
||||||
Text(
|
Text(
|
||||||
barcode!.code,
|
barcode.code,
|
||||||
style: kMediumHeadingStyle,
|
style: kMediumHeadingStyle,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
|
@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:simplex_chat/widgets/message_bubble.dart';
|
import 'package:simplex_chat/widgets/message_bubble.dart';
|
||||||
|
|
||||||
class ConversationView extends StatefulWidget {
|
class ConversationView extends StatefulWidget {
|
||||||
final String? name;
|
final String name;
|
||||||
const ConversationView({Key? key, @required this.name}) : super(key: key);
|
const ConversationView({Key key, @required this.name}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_ConversationViewState createState() => _ConversationViewState();
|
_ConversationViewState createState() => _ConversationViewState();
|
||||||
@ -13,17 +13,17 @@ class _ConversationViewState extends State<ConversationView> {
|
|||||||
final ScrollController _scrollController = ScrollController();
|
final ScrollController _scrollController = ScrollController();
|
||||||
final TextEditingController _messageFieldController = TextEditingController();
|
final TextEditingController _messageFieldController = TextEditingController();
|
||||||
|
|
||||||
FocusNode? _focus;
|
FocusNode _focus;
|
||||||
bool _fieldEnabled = false;
|
bool _fieldEnabled = false;
|
||||||
final List<Widget> _chatMessages = [];
|
final List<Widget> _chatMessages = [];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_focus = FocusNode();
|
_focus = FocusNode();
|
||||||
_focus!.addListener(() {
|
_focus.addListener(() {
|
||||||
debugPrint('FOCUS ${_focus!.hasFocus}');
|
debugPrint('FOCUS ${_focus.hasFocus}');
|
||||||
_fieldEnabled = _focus!.hasFocus;
|
_fieldEnabled = _focus.hasFocus;
|
||||||
debugPrint('MESSAGE ENABLED! $_fieldEnabled');
|
debugPrint('MESSAGE ENABLED $_fieldEnabled');
|
||||||
});
|
});
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
@ -32,7 +32,7 @@ class _ConversationViewState extends State<ConversationView> {
|
|||||||
void dispose() {
|
void dispose() {
|
||||||
_messageFieldController.dispose();
|
_messageFieldController.dispose();
|
||||||
_scrollController.dispose();
|
_scrollController.dispose();
|
||||||
_focus!.dispose();
|
_focus.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ class _ConversationViewState extends State<ConversationView> {
|
|||||||
onTap: () => FocusScope.of(context).unfocus(),
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('${widget.name}'),
|
title: Text(widget.name),
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
@ -50,7 +50,7 @@ class _ConversationViewState extends State<ConversationView> {
|
|||||||
child: Container(
|
child: Container(
|
||||||
child: _chatMessages.isEmpty
|
child: _chatMessages.isEmpty
|
||||||
? const Center(
|
? const Center(
|
||||||
child: Text('Send a message to get started!'),
|
child: Text('Send a message to get started'),
|
||||||
)
|
)
|
||||||
: SingleChildScrollView(
|
: SingleChildScrollView(
|
||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
@ -96,7 +96,7 @@ class _ConversationViewState extends State<ConversationView> {
|
|||||||
const SizedBox(width: 15.0),
|
const SizedBox(width: 15.0),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
if (_messageFieldController.text != '') {
|
if (_messageFieldController.text == '') {
|
||||||
setState(() {
|
setState(() {
|
||||||
_chatMessages.add(MessageBubble(
|
_chatMessages.add(MessageBubble(
|
||||||
isUser: true,
|
isUser: true,
|
||||||
@ -105,7 +105,7 @@ class _ConversationViewState extends State<ConversationView> {
|
|||||||
));
|
));
|
||||||
});
|
});
|
||||||
_messageFieldController.clear();
|
_messageFieldController.clear();
|
||||||
_focus!.unfocus();
|
_focus.unfocus();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: const Icon(Icons.send_rounded,
|
child: const Icon(Icons.send_rounded,
|
||||||
|
@ -9,34 +9,61 @@ import 'package:simplex_chat/model/group.dart';
|
|||||||
import 'package:simplex_chat/widgets/custom_text_field.dart';
|
import 'package:simplex_chat/widgets/custom_text_field.dart';
|
||||||
|
|
||||||
class AddGroupView extends StatefulWidget {
|
class AddGroupView extends StatefulWidget {
|
||||||
const AddGroupView({Key? key}) : super(key: key);
|
const AddGroupView({Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_AddGroupViewState createState() => _AddGroupViewState();
|
_AddGroupViewState createState() => _AddGroupViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AddGroupViewState extends State<AddGroupView> {
|
class _AddGroupViewState extends State<AddGroupView> {
|
||||||
bool _addMember = false;
|
// Image Picker --> DP properties
|
||||||
List<Contact> _contactsList = []; // for storing contacts
|
final imgPicker = ImagePicker();
|
||||||
|
File image;
|
||||||
|
String _groupPhotoPath = '';
|
||||||
|
bool _uploading = false;
|
||||||
|
bool _imageUploaded = false;
|
||||||
|
|
||||||
final List _members = [];
|
final List _members = [];
|
||||||
|
|
||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
final _displayNameController = TextEditingController();
|
final _displayNameController = TextEditingController();
|
||||||
final _descController = TextEditingController();
|
final _descController = TextEditingController();
|
||||||
|
|
||||||
// getting data from local storage FOR NOW!!
|
bool _addMember = false;
|
||||||
|
List<Contact> _contactsList = []; // for storing contacts
|
||||||
|
|
||||||
|
// image buttons options
|
||||||
|
final _dpBtnText = ['Remove', 'Gallery', 'Camera'];
|
||||||
|
final _dpBtnColors = [Colors.red, Colors.purple, Colors.green];
|
||||||
|
final _dpBtnIcons = [
|
||||||
|
Icons.delete,
|
||||||
|
Icons.photo_rounded,
|
||||||
|
Icons.camera_alt_rounded
|
||||||
|
];
|
||||||
|
|
||||||
|
// getting data from local storage FOR NOW
|
||||||
void _getContacts() async {
|
void _getContacts() async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
final String? _contacts = prefs.getString('contacts');
|
final String _contacts = prefs.getString('contacts');
|
||||||
setState(() {
|
setState(() {
|
||||||
_contactsList = List.from(Contact.decode(_contacts));
|
_contactsList = List.from(Contact.decode(_contacts));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _userPhotoPath = '';
|
||||||
|
void _getUserPhoto() async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
String _photo = prefs.getString('photo${prefs.getString('displayName')}');
|
||||||
|
if (_photo != null) {
|
||||||
|
setState(() {
|
||||||
|
_userPhotoPath = _photo;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
debugPrint(_userPhotoPath);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
_getUserPhoto();
|
||||||
_getContacts();
|
_getContacts();
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
@ -68,8 +95,50 @@ class _AddGroupViewState extends State<AddGroupView> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 10.0),
|
const SizedBox(height: 10.0),
|
||||||
const Center(
|
Center(
|
||||||
child: GroupDP(),
|
child: SizedBox(
|
||||||
|
height: 180.0,
|
||||||
|
width: 180.0,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
_imageUploaded
|
||||||
|
? CircleAvatar(
|
||||||
|
radius: 100.0,
|
||||||
|
backgroundImage:
|
||||||
|
FileImage(File(_groupPhotoPath)),
|
||||||
|
)
|
||||||
|
: const CircleAvatar(
|
||||||
|
radius: 100.0,
|
||||||
|
backgroundImage: AssetImage('assets/dp.png'),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
child: FloatingActionButton(
|
||||||
|
backgroundColor: kSecondaryColor,
|
||||||
|
elevation: 2.0,
|
||||||
|
mini: true,
|
||||||
|
onPressed: _updateProfilePic,
|
||||||
|
child: _uploading
|
||||||
|
? const SizedBox(
|
||||||
|
height: 18.0,
|
||||||
|
width: 18.0,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 2.0,
|
||||||
|
valueColor:
|
||||||
|
AlwaysStoppedAnimation<Color>(
|
||||||
|
Colors.white),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const Icon(
|
||||||
|
Icons.add_a_photo,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 25.0),
|
const SizedBox(height: 25.0),
|
||||||
const Text('Group Name', style: kSmallHeadingStyle),
|
const Text('Group Name', style: kSmallHeadingStyle),
|
||||||
@ -79,8 +148,8 @@ class _AddGroupViewState extends State<AddGroupView> {
|
|||||||
textInputType: TextInputType.name,
|
textInputType: TextInputType.name,
|
||||||
hintText: 'e.g College friends',
|
hintText: 'e.g College friends',
|
||||||
validatorFtn: (value) {
|
validatorFtn: (value) {
|
||||||
if (value!.isEmpty) {
|
if (value.isEmpty) {
|
||||||
return 'Group name cannot be empty!';
|
return 'Group name cannot be empty';
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
@ -148,10 +217,10 @@ class _AddGroupViewState extends State<AddGroupView> {
|
|||||||
leading: const CircleAvatar(
|
leading: const CircleAvatar(
|
||||||
backgroundImage: AssetImage('assets/dp.png'),
|
backgroundImage: AssetImage('assets/dp.png'),
|
||||||
),
|
),
|
||||||
title: Text(_contactsList[index].name!),
|
title: Text(_contactsList[index].name),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_members.add(_contactsList[index].name!);
|
_members.add(_contactsList[index].name);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -159,12 +228,14 @@ class _AddGroupViewState extends State<AddGroupView> {
|
|||||||
)
|
)
|
||||||
: Container(),
|
: Container(),
|
||||||
const Divider(height: 30.0),
|
const Divider(height: 30.0),
|
||||||
const ListTile(
|
ListTile(
|
||||||
leading: CircleAvatar(
|
leading: CircleAvatar(
|
||||||
backgroundImage: AssetImage('assets/dp.png'),
|
backgroundImage: _userPhotoPath == ''
|
||||||
|
? const AssetImage('assets/dp.png') as ImageProvider
|
||||||
|
: FileImage(File(_userPhotoPath)),
|
||||||
),
|
),
|
||||||
title: Text('You'),
|
title: const Text('You'),
|
||||||
subtitle: Text(
|
subtitle: const Text(
|
||||||
'Owner',
|
'Owner',
|
||||||
style: TextStyle(color: Colors.grey, fontSize: 12.0),
|
style: TextStyle(color: Colors.grey, fontSize: 12.0),
|
||||||
)),
|
)),
|
||||||
@ -178,9 +249,11 @@ class _AddGroupViewState extends State<AddGroupView> {
|
|||||||
child: FloatingActionButton(
|
child: FloatingActionButton(
|
||||||
heroTag: 'setup',
|
heroTag: 'setup',
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
if (_formKey.currentState!.validate()) {
|
if (_formKey.currentState.validate()) {
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
_addNewGroup(_displayNameController.text.trim(),
|
_addNewGroup(
|
||||||
|
_groupPhotoPath,
|
||||||
|
_displayNameController.text.trim(),
|
||||||
_descController.text.trim());
|
_descController.text.trim());
|
||||||
_descController.clear();
|
_descController.clear();
|
||||||
_displayNameController.clear();
|
_displayNameController.clear();
|
||||||
@ -194,102 +267,6 @@ class _AddGroupViewState extends State<AddGroupView> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _addNewGroup(String name, String desc) async {
|
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
||||||
List<Group> _localList = [];
|
|
||||||
_localList = List.from(Group.decode(prefs.getString('groups')));
|
|
||||||
|
|
||||||
List<Group> _groups = [
|
|
||||||
Group(
|
|
||||||
groupName: name,
|
|
||||||
groupDescription: desc,
|
|
||||||
members: _members,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
_groups = _localList + _groups;
|
|
||||||
|
|
||||||
final String _newGroups = Group.encode(_groups);
|
|
||||||
|
|
||||||
await prefs.setString('groups', _newGroups);
|
|
||||||
|
|
||||||
var snackBar = SnackBar(
|
|
||||||
backgroundColor: Colors.green,
|
|
||||||
content: Text('$name added!'),
|
|
||||||
);
|
|
||||||
ScaffoldMessenger.of(context)
|
|
||||||
..hideCurrentSnackBar()
|
|
||||||
..showSnackBar(snackBar);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GroupDP extends StatefulWidget {
|
|
||||||
const GroupDP({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
_GroupDPState createState() => _GroupDPState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _GroupDPState extends State<GroupDP> {
|
|
||||||
// Image Picker --> DP properties
|
|
||||||
final imgPicker = ImagePicker();
|
|
||||||
File? image;
|
|
||||||
String photoUrl = '';
|
|
||||||
bool _uploading = false;
|
|
||||||
bool _imageUploaded = false;
|
|
||||||
|
|
||||||
// image buttons options
|
|
||||||
final _dpBtnText = ['Remove', 'Gallery', 'Camera'];
|
|
||||||
final _dpBtnColors = [Colors.red, Colors.purple, Colors.green];
|
|
||||||
final _dpBtnIcons = [
|
|
||||||
Icons.delete,
|
|
||||||
Icons.photo_rounded,
|
|
||||||
Icons.camera_alt_rounded
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return SizedBox(
|
|
||||||
height: 180.0,
|
|
||||||
width: 180.0,
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
_imageUploaded
|
|
||||||
? CircleAvatar(
|
|
||||||
radius: 100.0,
|
|
||||||
backgroundImage: FileImage(image!),
|
|
||||||
)
|
|
||||||
: const CircleAvatar(
|
|
||||||
radius: 100.0,
|
|
||||||
backgroundImage: AssetImage('assets/dp.png'),
|
|
||||||
),
|
|
||||||
Positioned(
|
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
|
||||||
child: FloatingActionButton(
|
|
||||||
backgroundColor: kSecondaryColor,
|
|
||||||
elevation: 2.0,
|
|
||||||
mini: true,
|
|
||||||
onPressed: _updateProfilePic,
|
|
||||||
child: _uploading
|
|
||||||
? const SizedBox(
|
|
||||||
height: 18.0,
|
|
||||||
width: 18.0,
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
strokeWidth: 2.0,
|
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: const Icon(
|
|
||||||
Icons.add_a_photo,
|
|
||||||
size: 20,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _updateProfilePic() {
|
void _updateProfilePic() {
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
@ -356,6 +333,7 @@ class _GroupDPState extends State<GroupDP> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
_imageUploaded = false;
|
_imageUploaded = false;
|
||||||
image = null;
|
image = null;
|
||||||
|
_groupPhotoPath = '';
|
||||||
});
|
});
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
@ -376,6 +354,7 @@ class _GroupDPState extends State<GroupDP> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
_uploading = false;
|
_uploading = false;
|
||||||
_imageUploaded = true;
|
_imageUploaded = true;
|
||||||
|
_groupPhotoPath = file.path;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -405,6 +384,7 @@ class _GroupDPState extends State<GroupDP> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
_uploading = false;
|
_uploading = false;
|
||||||
_imageUploaded = true;
|
_imageUploaded = true;
|
||||||
|
_groupPhotoPath = file.path;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -417,4 +397,34 @@ class _GroupDPState extends State<GroupDP> {
|
|||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _addNewGroup(String photo, String name, String desc) async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
List<Group> _localList = [];
|
||||||
|
final String _local = prefs.getString('groups');
|
||||||
|
if (_local != null) {
|
||||||
|
_localList = List.from(Group.decode(_local));
|
||||||
|
}
|
||||||
|
List<Group> _groups = [
|
||||||
|
Group(
|
||||||
|
photoPath: _groupPhotoPath,
|
||||||
|
groupName: name,
|
||||||
|
groupDescription: desc,
|
||||||
|
members: _members,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
_groups = _localList + _groups;
|
||||||
|
|
||||||
|
final String _newGroups = Group.encode(_groups);
|
||||||
|
|
||||||
|
await prefs.setString('groups', _newGroups);
|
||||||
|
|
||||||
|
var snackBar = SnackBar(
|
||||||
|
backgroundColor: Colors.green,
|
||||||
|
content: Text('$name added'),
|
||||||
|
);
|
||||||
|
ScaffoldMessenger.of(context)
|
||||||
|
..hideCurrentSnackBar()
|
||||||
|
..showSnackBar(snackBar);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:simplex_chat/animations/bottom_animation.dart';
|
import 'package:simplex_chat/animations/bottom_animation.dart';
|
||||||
import 'package:simplex_chat/app_routes.dart';
|
import 'package:simplex_chat/app_routes.dart';
|
||||||
@ -8,14 +9,14 @@ import 'package:simplex_chat/model/group.dart';
|
|||||||
import 'package:simplex_chat/views/conversation/conversation_view.dart';
|
import 'package:simplex_chat/views/conversation/conversation_view.dart';
|
||||||
|
|
||||||
class GroupView extends StatefulWidget {
|
class GroupView extends StatefulWidget {
|
||||||
const GroupView({Key? key}) : super(key: key);
|
const GroupView({Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<GroupView> createState() => _GroupViewState();
|
State<GroupView> createState() => _GroupViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _GroupViewState extends State<GroupView> {
|
class _GroupViewState extends State<GroupView> {
|
||||||
bool? _eraseMedia = false;
|
bool _eraseMedia = false;
|
||||||
final List<String> _options = [
|
final List<String> _options = [
|
||||||
'Add group',
|
'Add group',
|
||||||
'Scan invitation',
|
'Scan invitation',
|
||||||
@ -42,14 +43,28 @@ class _GroupViewState extends State<GroupView> {
|
|||||||
// getting data from local storage FOR NOW!!
|
// getting data from local storage FOR NOW!!
|
||||||
void _getGroups() async {
|
void _getGroups() async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
final String? _groups = prefs.getString('groups');
|
final String _groups = prefs.getString('groups');
|
||||||
|
if (_groups != null) {
|
||||||
|
setState(() {
|
||||||
|
_groupList = List.from(Group.decode(_groups));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _photo = '';
|
||||||
|
String _displayName = '';
|
||||||
|
|
||||||
|
void _getUserData() async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
setState(() {
|
setState(() {
|
||||||
_groupList = List.from(Group.decode(_groups));
|
_displayName = prefs.getString('displayName');
|
||||||
|
_photo = prefs.getString('photo$_displayName');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
_getUserData();
|
||||||
_getGroups();
|
_getGroups();
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
@ -62,15 +77,23 @@ class _GroupViewState extends State<GroupView> {
|
|||||||
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0),
|
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Align(
|
Row(
|
||||||
alignment: Alignment.centerRight,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
child: GestureDetector(
|
children: [
|
||||||
onTap: _addNewGroups,
|
Column(
|
||||||
child: SvgPicture.asset(
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
'assets/logo.svg',
|
children: [
|
||||||
height: 40.0,
|
Text('Hi! $_displayName', style: kSmallHeadingStyle),
|
||||||
|
const Text('Good day!'),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(width: 10.0),
|
||||||
|
CircleAvatar(
|
||||||
|
backgroundImage: _photo.isEmpty
|
||||||
|
? const AssetImage('assets/dp.png') as ImageProvider
|
||||||
|
: FileImage(File(_photo)),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 15.0),
|
const SizedBox(height: 15.0),
|
||||||
Row(
|
Row(
|
||||||
@ -111,11 +134,14 @@ class _GroupViewState extends State<GroupView> {
|
|||||||
_groupList.length,
|
_groupList.length,
|
||||||
(index) => WidgetAnimator(
|
(index) => WidgetAnimator(
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: const CircleAvatar(
|
leading: CircleAvatar(
|
||||||
backgroundImage: AssetImage('assets/dp.png'),
|
backgroundImage: _groupList[index].photoPath == ''
|
||||||
|
? const AssetImage('assets/dp.png')
|
||||||
|
as ImageProvider
|
||||||
|
: FileImage(File(_groupList[index].photoPath)),
|
||||||
),
|
),
|
||||||
title: Text(_groupList[index].groupName!),
|
title: Text(_groupList[index].groupName),
|
||||||
subtitle: Text(_groupList[index].groupDescription!),
|
subtitle: Text(_groupList[index].groupDescription),
|
||||||
trailing: Text(
|
trailing: Text(
|
||||||
'Members: ${_groupList[index].members.length}',
|
'Members: ${_groupList[index].members.length}',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@ -296,10 +322,14 @@ class _GroupViewState extends State<GroupView> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// dummy ftn for loading new contacts
|
// dummy ftn for loading new contacts
|
||||||
|
// ignore: unused_element
|
||||||
void _addNewGroups() async {
|
void _addNewGroups() async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
List<Group> _localList = [];
|
List<Group> _localList = [];
|
||||||
_localList = List.from(Group.decode(prefs.getString('groups')));
|
final String _local = prefs.getString('groups');
|
||||||
|
if (_local != null) {
|
||||||
|
_localList = List.from(Group.decode(_local));
|
||||||
|
}
|
||||||
|
|
||||||
List<Group> _groups = [
|
List<Group> _groups = [
|
||||||
Group(
|
Group(
|
||||||
|
@ -7,19 +7,17 @@ import 'package:simplex_chat/constants.dart';
|
|||||||
import 'package:simplex_chat/providers/drawer_providers.dart';
|
import 'package:simplex_chat/providers/drawer_providers.dart';
|
||||||
|
|
||||||
class MyDrawer extends StatelessWidget {
|
class MyDrawer extends StatelessWidget {
|
||||||
final AnimationController? animationController;
|
const MyDrawer({Key key}) : super(key: key);
|
||||||
const MyDrawer({Key? key, this.animationController}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final _drawerProviders = Provider.of<DrawerProvider>(context);
|
final _drawerProviders = Provider.of<DrawerProvider>(context);
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: MediaQuery.of(context).size.width * 0.82,
|
width: MediaQuery.of(context).size.width * 0.82,
|
||||||
child: Material(
|
child: Padding(
|
||||||
color: Colors.white,
|
padding: const EdgeInsets.all(10.0),
|
||||||
child: Padding(
|
child: Builder(builder: (context) {
|
||||||
padding: const EdgeInsets.all(10.0),
|
return Column(
|
||||||
child: Column(
|
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 30.0),
|
const SizedBox(height: 30.0),
|
||||||
SvgPicture.asset(
|
SvgPicture.asset(
|
||||||
@ -32,30 +30,22 @@ class MyDrawer extends StatelessWidget {
|
|||||||
? kPrimaryColor
|
? kPrimaryColor
|
||||||
: Colors.transparent,
|
: Colors.transparent,
|
||||||
leading: Icon(
|
leading: Icon(
|
||||||
Icons.contact_phone,
|
Icons.person,
|
||||||
color: _drawerProviders.currentIndex == 0
|
color: _drawerProviders.currentIndex == 0
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: Colors.grey,
|
: Colors.grey,
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Your contacts',
|
'Your Profile',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: _drawerProviders.currentIndex == 0
|
color: _drawerProviders.currentIndex == 0
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: Colors.black,
|
: Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
|
||||||
'Start a conversation right away!',
|
|
||||||
style: TextStyle(
|
|
||||||
color: _drawerProviders.currentIndex == 0
|
|
||||||
? Colors.white
|
|
||||||
: Colors.grey,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_drawerProviders.currentIndex = 0;
|
_drawerProviders.currentIndex = 0;
|
||||||
_drawerProviders.toggle(animationController);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
@ -63,30 +53,22 @@ class MyDrawer extends StatelessWidget {
|
|||||||
? kPrimaryColor
|
? kPrimaryColor
|
||||||
: Colors.transparent,
|
: Colors.transparent,
|
||||||
leading: Icon(
|
leading: Icon(
|
||||||
Icons.insert_invitation,
|
Icons.contact_phone,
|
||||||
color: _drawerProviders.currentIndex == 1
|
color: _drawerProviders.currentIndex == 1
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: Colors.grey,
|
: Colors.grey,
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Invitations',
|
'Your contacts',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: _drawerProviders.currentIndex == 1
|
color: _drawerProviders.currentIndex == 1
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: Colors.black,
|
: Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
|
||||||
'Increase your contact circle!',
|
|
||||||
style: TextStyle(
|
|
||||||
color: _drawerProviders.currentIndex == 1
|
|
||||||
? Colors.white
|
|
||||||
: Colors.grey,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_drawerProviders.currentIndex = 1;
|
_drawerProviders.currentIndex = 1;
|
||||||
_drawerProviders.toggle(animationController);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
@ -94,47 +76,62 @@ class MyDrawer extends StatelessWidget {
|
|||||||
? kPrimaryColor
|
? kPrimaryColor
|
||||||
: Colors.transparent,
|
: Colors.transparent,
|
||||||
leading: Icon(
|
leading: Icon(
|
||||||
Icons.group,
|
Icons.insert_invitation,
|
||||||
color: _drawerProviders.currentIndex == 2
|
color: _drawerProviders.currentIndex == 2
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: Colors.grey,
|
: Colors.grey,
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Your groups',
|
'Invitations',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: _drawerProviders.currentIndex == 2
|
color: _drawerProviders.currentIndex == 2
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: Colors.black,
|
: Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
onTap: () {
|
||||||
'Get in touch with numbers!',
|
_drawerProviders.currentIndex = 2;
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
tileColor: _drawerProviders.currentIndex == 3
|
||||||
|
? kPrimaryColor
|
||||||
|
: Colors.transparent,
|
||||||
|
leading: Icon(
|
||||||
|
Icons.group,
|
||||||
|
color: _drawerProviders.currentIndex == 3
|
||||||
|
? Colors.white
|
||||||
|
: Colors.grey,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
'Your groups',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: _drawerProviders.currentIndex == 2
|
color: _drawerProviders.currentIndex == 3
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: Colors.grey,
|
: Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_drawerProviders.currentIndex = 2;
|
_drawerProviders.currentIndex = 3;
|
||||||
_drawerProviders.toggle(animationController);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.exit_to_app_rounded),
|
leading: const Icon(Icons.refresh),
|
||||||
title: const Text('Logout'),
|
title: const Text('Switch Profile'),
|
||||||
subtitle: const Text('Good bye! See you soon :)'),
|
subtitle: const Text('*Not supported yet!*'),
|
||||||
onTap: () => _logout(context),
|
onTap: () => _switchProfile(context),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
);
|
||||||
),
|
}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _logout(BuildContext context) async {
|
void _switchProfile(BuildContext context) async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
await Navigator.pushNamedAndRemoveUntil(
|
await Navigator.pushNamedAndRemoveUntil(
|
||||||
@ -142,7 +139,7 @@ class MyDrawer extends StatelessWidget {
|
|||||||
AppRoutes.setupProfile,
|
AppRoutes.setupProfile,
|
||||||
(route) => route.settings.name == AppRoutes.setupProfile ? true : false,
|
(route) => route.settings.name == AppRoutes.setupProfile ? true : false,
|
||||||
);
|
);
|
||||||
String? _name = prefs.getString('displayName');
|
String _name = prefs.getString('displayName');
|
||||||
await prefs.remove('displayName');
|
await prefs.remove('displayName');
|
||||||
await prefs.remove('fullName');
|
await prefs.remove('fullName');
|
||||||
await prefs.remove('photo$_name');
|
await prefs.remove('photo$_name');
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'dart:math' as math;
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
@ -9,138 +8,60 @@ import 'package:simplex_chat/views/contacts/contacts_view.dart';
|
|||||||
import 'package:simplex_chat/views/group/group_view.dart';
|
import 'package:simplex_chat/views/group/group_view.dart';
|
||||||
import 'package:simplex_chat/views/home/drawer.dart';
|
import 'package:simplex_chat/views/home/drawer.dart';
|
||||||
import 'package:simplex_chat/views/invitations/invitation_view.dart';
|
import 'package:simplex_chat/views/invitations/invitation_view.dart';
|
||||||
|
import 'package:simplex_chat/views/profile/profile_view.dart';
|
||||||
|
|
||||||
class HomeView extends StatefulWidget {
|
class HomeView extends StatefulWidget {
|
||||||
final double? maxSlide;
|
final double maxSlide;
|
||||||
const HomeView({
|
const HomeView({Key key, this.maxSlide}) : super(key: key);
|
||||||
Key? key,
|
|
||||||
this.maxSlide,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_HomeViewState createState() => _HomeViewState();
|
_HomeViewState createState() => _HomeViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HomeViewState extends State<HomeView> with TickerProviderStateMixin {
|
class _HomeViewState extends State<HomeView> {
|
||||||
AnimationController? animationController;
|
|
||||||
bool? _canBeDragged;
|
|
||||||
|
|
||||||
// views
|
// views
|
||||||
final List<Widget> _views = [
|
final List<Widget> _views = [
|
||||||
|
const ProfileView(),
|
||||||
const ContactsView(),
|
const ContactsView(),
|
||||||
const Invitations(),
|
const Invitations(),
|
||||||
const GroupView(),
|
const GroupView(),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
|
|
||||||
animationController = AnimationController(
|
|
||||||
vsync: this, duration: const Duration(milliseconds: 250));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final _drawerProviders = Provider.of<DrawerProvider>(context);
|
final _drawerProviders = Provider.of<DrawerProvider>(context);
|
||||||
return WillPopScope(
|
return WillPopScope(
|
||||||
onWillPop: _onWillPop,
|
onWillPop: _onWillPop,
|
||||||
child: GestureDetector(
|
child: SafeArea(
|
||||||
onHorizontalDragStart: _onDragStart,
|
child: Scaffold(
|
||||||
onHorizontalDragUpdate: _onDragUpdate,
|
drawer: const Drawer(
|
||||||
onHorizontalDragEnd: _onDragEnd,
|
child: MyDrawer(),
|
||||||
behavior: HitTestBehavior.translucent,
|
),
|
||||||
child: AnimatedBuilder(
|
body: Builder(builder: (context) {
|
||||||
animation: animationController!,
|
return Stack(
|
||||||
builder: (context, _) {
|
children: [
|
||||||
return Material(
|
_views[_drawerProviders.currentIndex],
|
||||||
color: Colors.white70,
|
Positioned(
|
||||||
child: SafeArea(
|
top: MediaQuery.of(context).size.height * 0.03,
|
||||||
child: Stack(
|
left: MediaQuery.of(context).size.width * 0.03,
|
||||||
children: [
|
child: InkWell(
|
||||||
Transform.translate(
|
onTap: () {
|
||||||
offset: Offset(
|
Scaffold.of(context).openDrawer();
|
||||||
widget.maxSlide! * (animationController!.value - 1),
|
},
|
||||||
0),
|
child: Padding(
|
||||||
child: Transform(
|
padding: const EdgeInsets.all(8.0),
|
||||||
transform: Matrix4.identity()
|
child: SvgPicture.asset('assets/menu.svg'),
|
||||||
..setEntry(3, 2, 0.001)
|
|
||||||
..rotateY(
|
|
||||||
math.pi / 2 * (1 - animationController!.value)),
|
|
||||||
alignment: Alignment.centerRight,
|
|
||||||
child: MyDrawer(
|
|
||||||
animationController: animationController,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Transform.translate(
|
),
|
||||||
offset: Offset(
|
|
||||||
widget.maxSlide! * animationController!.value, 0),
|
|
||||||
child: Transform(
|
|
||||||
transform: Matrix4.identity()
|
|
||||||
..setEntry(3, 2, 0.001)
|
|
||||||
..rotateY(
|
|
||||||
-math.pi / 2 * animationController!.value),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: _views[_drawerProviders.currentIndex]),
|
|
||||||
),
|
|
||||||
Positioned(
|
|
||||||
top: MediaQuery.of(context).padding.top,
|
|
||||||
left: MediaQuery.of(context).size.width * 0.03 +
|
|
||||||
animationController!.value * widget.maxSlide!,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () {
|
|
||||||
_drawerProviders.toggle(animationController);
|
|
||||||
},
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: SvgPicture.asset(
|
|
||||||
'assets/menu.svg',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
);
|
);
|
||||||
},
|
}),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onDragStart(DragStartDetails details) {
|
|
||||||
bool isDragOpenFromLeft = animationController!.isDismissed;
|
|
||||||
bool isDragCloseFromRight = animationController!.isCompleted;
|
|
||||||
_canBeDragged = isDragOpenFromLeft || isDragCloseFromRight;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onDragUpdate(DragUpdateDetails details) {
|
|
||||||
if (_canBeDragged!) {
|
|
||||||
double delta = details.primaryDelta! / widget.maxSlide!;
|
|
||||||
animationController!.value += delta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onDragEnd(DragEndDetails details) {
|
|
||||||
double _kMinFlingVelocity = 365.0;
|
|
||||||
|
|
||||||
if (animationController!.isDismissed || animationController!.isCompleted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (details.velocity.pixelsPerSecond.dx.abs() >= _kMinFlingVelocity) {
|
|
||||||
double visualVelocity = details.velocity.pixelsPerSecond.dx /
|
|
||||||
MediaQuery.of(context).size.width;
|
|
||||||
|
|
||||||
animationController!.fling(velocity: visualVelocity);
|
|
||||||
} else if (animationController!.value < 0.5) {
|
|
||||||
animationController!.reverse();
|
|
||||||
} else {
|
|
||||||
animationController!.forward();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> _onWillPop() async {
|
Future<bool> _onWillPop() async {
|
||||||
return (await showDialog(
|
return (await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -1,9 +1,33 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:simplex_chat/constants.dart';
|
import 'package:simplex_chat/constants.dart';
|
||||||
|
|
||||||
class Invitations extends StatelessWidget {
|
class Invitations extends StatefulWidget {
|
||||||
const Invitations({Key? key}) : super(key: key);
|
const Invitations({Key key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<Invitations> createState() => _InvitationsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _InvitationsState extends State<Invitations> {
|
||||||
|
String _photo = '';
|
||||||
|
String _displayName = '';
|
||||||
|
|
||||||
|
void _getUserData() async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
setState(() {
|
||||||
|
_displayName = prefs.getString('displayName');
|
||||||
|
_photo = prefs.getString('photo$_displayName');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_getUserData();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -13,12 +37,23 @@ class Invitations extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0),
|
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Align(
|
Row(
|
||||||
alignment: Alignment.centerRight,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
child: SvgPicture.asset(
|
children: [
|
||||||
'assets/logo.svg',
|
Column(
|
||||||
height: 40.0,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
),
|
children: [
|
||||||
|
Text('Hi! $_displayName', style: kSmallHeadingStyle),
|
||||||
|
const Text('Good day!'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10.0),
|
||||||
|
CircleAvatar(
|
||||||
|
backgroundImage: _photo.isEmpty
|
||||||
|
? const AssetImage('assets/dp.png') as ImageProvider
|
||||||
|
: FileImage(File(_photo)),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 15.0),
|
const SizedBox(height: 15.0),
|
||||||
Row(
|
Row(
|
||||||
|
@ -4,7 +4,7 @@ import 'package:simplex_chat/app_routes.dart';
|
|||||||
import 'package:simplex_chat/constants.dart';
|
import 'package:simplex_chat/constants.dart';
|
||||||
|
|
||||||
class IntroView extends StatelessWidget {
|
class IntroView extends StatelessWidget {
|
||||||
const IntroView({Key? key}) : super(key: key);
|
const IntroView({Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
318
packages/simplex_app/lib/views/profile/profile_view.dart
Normal file
318
packages/simplex_app/lib/views/profile/profile_view.dart
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:simplex_chat/constants.dart';
|
||||||
|
import 'package:simplex_chat/widgets/custom_text_field.dart';
|
||||||
|
|
||||||
|
class ProfileView extends StatefulWidget {
|
||||||
|
const ProfileView({Key key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_ProfileViewState createState() => _ProfileViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ProfileViewState extends State<ProfileView> {
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
// controllers
|
||||||
|
final TextEditingController _displayNameController = TextEditingController();
|
||||||
|
final TextEditingController _fullNameController = TextEditingController();
|
||||||
|
|
||||||
|
// Image Picker --> DP properties
|
||||||
|
final imgPicker = ImagePicker();
|
||||||
|
File image;
|
||||||
|
String _photo = '';
|
||||||
|
bool _uploading = false;
|
||||||
|
|
||||||
|
// image buttons options
|
||||||
|
final _dpBtnText = ['Remove', 'Gallery', 'Camera'];
|
||||||
|
final _dpBtnColors = [Colors.red, Colors.purple, Colors.green];
|
||||||
|
final _dpBtnIcons = [
|
||||||
|
Icons.delete,
|
||||||
|
Icons.photo_rounded,
|
||||||
|
Icons.camera_alt_rounded
|
||||||
|
];
|
||||||
|
|
||||||
|
String _displayName = '';
|
||||||
|
String _fullName = '';
|
||||||
|
|
||||||
|
void _getUserData() async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
setState(() {
|
||||||
|
_fullName = prefs.getString('fullName');
|
||||||
|
_displayName = prefs.getString('displayName');
|
||||||
|
_photo = prefs.getString('photo$_displayName');
|
||||||
|
});
|
||||||
|
_displayNameController.text = _displayName;
|
||||||
|
if (_fullName != null) _fullNameController.text = _fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_getUserData();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_displayNameController.dispose();
|
||||||
|
_fullNameController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: GestureDetector(
|
||||||
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
|
child: SafeArea(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(12.0),
|
||||||
|
child: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
Center(
|
||||||
|
child: SizedBox(
|
||||||
|
height: 180.0,
|
||||||
|
width: 180.0,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
_photo != ''
|
||||||
|
? CircleAvatar(
|
||||||
|
radius: 100.0,
|
||||||
|
backgroundImage: FileImage(File(_photo)),
|
||||||
|
)
|
||||||
|
: const CircleAvatar(
|
||||||
|
radius: 100.0,
|
||||||
|
backgroundImage: AssetImage('assets/dp.png'),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
child: FloatingActionButton(
|
||||||
|
backgroundColor: kSecondaryColor,
|
||||||
|
elevation: 2.0,
|
||||||
|
mini: true,
|
||||||
|
onPressed: _updateProfilePic,
|
||||||
|
child: _uploading
|
||||||
|
? const SizedBox(
|
||||||
|
height: 18.0,
|
||||||
|
width: 18.0,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 2.0,
|
||||||
|
valueColor:
|
||||||
|
AlwaysStoppedAnimation<Color>(
|
||||||
|
Colors.white),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const Icon(
|
||||||
|
Icons.add_a_photo,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
const SizedBox(height: 25.0),
|
||||||
|
const Text('Display Name', style: kSmallHeadingStyle),
|
||||||
|
const SizedBox(height: 10.0),
|
||||||
|
CustomTextField(
|
||||||
|
textEditingController: _displayNameController,
|
||||||
|
textInputType: TextInputType.name,
|
||||||
|
hintText: 'e.g John',
|
||||||
|
validatorFtn: (value) {
|
||||||
|
if (value.isEmpty) {
|
||||||
|
return 'Display name cannot be empty';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 25.0),
|
||||||
|
const Text('Full Name', style: kSmallHeadingStyle),
|
||||||
|
const SizedBox(height: 10.0),
|
||||||
|
CustomTextField(
|
||||||
|
textEditingController: _fullNameController,
|
||||||
|
textInputType: TextInputType.name,
|
||||||
|
hintText: 'e.g John Doe',
|
||||||
|
),
|
||||||
|
const SizedBox(height: 25.0),
|
||||||
|
const Text(
|
||||||
|
'Your display name is what your contact will know you :)',
|
||||||
|
style: TextStyle(letterSpacing: 1.2),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
floatingActionButton: Visibility(
|
||||||
|
visible: MediaQuery.of(context).viewInsets.bottom == 0,
|
||||||
|
child: FloatingActionButton(
|
||||||
|
heroTag: 'setup',
|
||||||
|
onPressed: () async {
|
||||||
|
if (_formKey.currentState.validate()) {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
await _createProfile();
|
||||||
|
const snackBar = SnackBar(
|
||||||
|
backgroundColor: Colors.green,
|
||||||
|
content: Text('Profile updated!'),
|
||||||
|
);
|
||||||
|
|
||||||
|
ScaffoldMessenger.of(context)
|
||||||
|
..hideCurrentSnackBar()
|
||||||
|
..showSnackBar(snackBar);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Icon(Icons.check),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create profile and store in local
|
||||||
|
Future<void> _createProfile() async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
await prefs.setString('displayName', _displayNameController.text.trim());
|
||||||
|
await prefs.setString('fullName', _fullNameController.text.trim());
|
||||||
|
await prefs.setString('photo${_displayNameController.text.trim()}', _photo);
|
||||||
|
|
||||||
|
debugPrint(prefs.getString('photo'));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateProfilePic() {
|
||||||
|
showModalBottomSheet(
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(10.0),
|
||||||
|
topRight: Radius.circular(10.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
context: context,
|
||||||
|
builder: (context) => Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 20.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey,
|
||||||
|
borderRadius: BorderRadius.circular(360.0)),
|
||||||
|
height: 7.0,
|
||||||
|
width: 50.0,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20.0),
|
||||||
|
const Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
' Profile photo',
|
||||||
|
style: kHeadingStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 15.0),
|
||||||
|
Row(
|
||||||
|
children: List.generate(
|
||||||
|
3,
|
||||||
|
(index) => Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
MaterialButton(
|
||||||
|
color: _dpBtnColors.map((e) => e).elementAt(index),
|
||||||
|
shape: const CircleBorder(),
|
||||||
|
onPressed: index == 0
|
||||||
|
? () => _removePic()
|
||||||
|
: index == 1
|
||||||
|
? () => _galleryPic()
|
||||||
|
: () => _cameraPic(),
|
||||||
|
child: Icon(
|
||||||
|
_dpBtnIcons.map((e) => e).elementAt(index),
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
_dpBtnText.map((e) => e).elementAt(index),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _removePic() {
|
||||||
|
setState(() {
|
||||||
|
image = null;
|
||||||
|
_photo = '';
|
||||||
|
});
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _cameraPic() async {
|
||||||
|
try {
|
||||||
|
setState(() {
|
||||||
|
_uploading = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// picking Image from Camera
|
||||||
|
final file = await imgPicker.getImage(
|
||||||
|
source: ImageSource.camera,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (file != null) {
|
||||||
|
image = File(file.path);
|
||||||
|
setState(() {
|
||||||
|
_uploading = false;
|
||||||
|
_photo = file.path;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
_uploading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Navigator.pop(context);
|
||||||
|
} catch (e) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _galleryPic() async {
|
||||||
|
try {
|
||||||
|
debugPrint('gallery pic');
|
||||||
|
setState(() {
|
||||||
|
_uploading = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// picking Image from local storage
|
||||||
|
final file = await imgPicker.getImage(
|
||||||
|
source: ImageSource.gallery,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (file != null) {
|
||||||
|
image = File(file.path);
|
||||||
|
setState(() {
|
||||||
|
_uploading = false;
|
||||||
|
_photo = file.path;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
_uploading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Navigator.pop(context);
|
||||||
|
} catch (e) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@ import 'package:simplex_chat/constants.dart';
|
|||||||
import 'package:simplex_chat/widgets/custom_btn.dart';
|
import 'package:simplex_chat/widgets/custom_btn.dart';
|
||||||
|
|
||||||
class ScanInvitationView extends StatelessWidget {
|
class ScanInvitationView extends StatelessWidget {
|
||||||
const ScanInvitationView({Key? key}) : super(key: key);
|
const ScanInvitationView({Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -8,7 +8,7 @@ import 'package:simplex_chat/views/home/home_view.dart';
|
|||||||
import 'package:simplex_chat/widgets/custom_text_field.dart';
|
import 'package:simplex_chat/widgets/custom_text_field.dart';
|
||||||
|
|
||||||
class SetupProfileView extends StatefulWidget {
|
class SetupProfileView extends StatefulWidget {
|
||||||
const SetupProfileView({Key? key}) : super(key: key);
|
const SetupProfileView({Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_SetupProfileViewState createState() => _SetupProfileViewState();
|
_SetupProfileViewState createState() => _SetupProfileViewState();
|
||||||
@ -22,7 +22,7 @@ class _SetupProfileViewState extends State<SetupProfileView> {
|
|||||||
|
|
||||||
// Image Picker --> DP properties
|
// Image Picker --> DP properties
|
||||||
final imgPicker = ImagePicker();
|
final imgPicker = ImagePicker();
|
||||||
File? image;
|
File image;
|
||||||
String photoUrl = '';
|
String photoUrl = '';
|
||||||
bool _uploading = false;
|
bool _uploading = false;
|
||||||
bool _imageUploaded = false;
|
bool _imageUploaded = false;
|
||||||
@ -63,7 +63,7 @@ class _SetupProfileViewState extends State<SetupProfileView> {
|
|||||||
_imageUploaded
|
_imageUploaded
|
||||||
? CircleAvatar(
|
? CircleAvatar(
|
||||||
radius: 100.0,
|
radius: 100.0,
|
||||||
backgroundImage: FileImage(image!),
|
backgroundImage: FileImage(image),
|
||||||
)
|
)
|
||||||
: const CircleAvatar(
|
: const CircleAvatar(
|
||||||
radius: 100.0,
|
radius: 100.0,
|
||||||
@ -105,8 +105,8 @@ class _SetupProfileViewState extends State<SetupProfileView> {
|
|||||||
textInputType: TextInputType.name,
|
textInputType: TextInputType.name,
|
||||||
hintText: 'e.g John',
|
hintText: 'e.g John',
|
||||||
validatorFtn: (value) {
|
validatorFtn: (value) {
|
||||||
if (value!.isEmpty) {
|
if (value.isEmpty) {
|
||||||
return 'Display name cannot be empty!';
|
return 'Display name cannot be empty';
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
@ -118,12 +118,6 @@ class _SetupProfileViewState extends State<SetupProfileView> {
|
|||||||
textEditingController: _fullNameController,
|
textEditingController: _fullNameController,
|
||||||
textInputType: TextInputType.name,
|
textInputType: TextInputType.name,
|
||||||
hintText: 'e.g John Doe',
|
hintText: 'e.g John Doe',
|
||||||
validatorFtn: (value) {
|
|
||||||
if (value!.isEmpty) {
|
|
||||||
return 'Full name cannot be empty!';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 25.0),
|
const SizedBox(height: 25.0),
|
||||||
const Text(
|
const Text(
|
||||||
@ -142,7 +136,7 @@ class _SetupProfileViewState extends State<SetupProfileView> {
|
|||||||
child: FloatingActionButton(
|
child: FloatingActionButton(
|
||||||
heroTag: 'setup',
|
heroTag: 'setup',
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
if (_formKey.currentState!.validate()) {
|
if (_formKey.currentState.validate()) {
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
|
|
||||||
await _createProfile();
|
await _createProfile();
|
||||||
@ -269,6 +263,7 @@ class _SetupProfileViewState extends State<SetupProfileView> {
|
|||||||
|
|
||||||
void _galleryPic() async {
|
void _galleryPic() async {
|
||||||
try {
|
try {
|
||||||
|
debugPrint('gallery pic');
|
||||||
setState(() {
|
setState(() {
|
||||||
_uploading = true;
|
_uploading = true;
|
||||||
});
|
});
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:progress_indicators/progress_indicators.dart';
|
import 'package:progress_indicators/progress_indicators.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
import 'package:simplex_chat/animations/entrance_fader.dart';
|
import 'package:simplex_chat/animations/entrance_fader.dart';
|
||||||
|
import 'package:simplex_chat/app_routes.dart';
|
||||||
import 'package:simplex_chat/constants.dart';
|
import 'package:simplex_chat/constants.dart';
|
||||||
import 'package:simplex_chat/views/home/home_view.dart';
|
|
||||||
import 'package:simplex_chat/views/onBoarding/intro_view.dart';
|
|
||||||
|
|
||||||
class SplashScreen extends StatefulWidget {
|
class SplashScreen extends StatefulWidget {
|
||||||
const SplashScreen({Key? key}) : super(key: key);
|
const SplashScreen({Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_SplashScreenState createState() => _SplashScreenState();
|
_SplashScreenState createState() => _SplashScreenState();
|
||||||
@ -16,19 +14,11 @@ class SplashScreen extends StatefulWidget {
|
|||||||
|
|
||||||
class _SplashScreenState extends State<SplashScreen> {
|
class _SplashScreenState extends State<SplashScreen> {
|
||||||
// logincheck
|
// logincheck
|
||||||
void _loginCheck() async {
|
void _loginCheck() {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
||||||
String? _name = prefs.getString('displayName');
|
|
||||||
Future.delayed(const Duration(seconds: 4), () {
|
Future.delayed(const Duration(seconds: 4), () {
|
||||||
Navigator.push(
|
Navigator.pushNamed(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
AppRoutes.intro,
|
||||||
builder: (_) => _name == null
|
|
||||||
? const IntroView()
|
|
||||||
: HomeView(
|
|
||||||
maxSlide: MediaQuery.of(context).size.width * 0.82,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -7,13 +7,13 @@ class CustomButton extends StatelessWidget {
|
|||||||
@required this.onPressed,
|
@required this.onPressed,
|
||||||
@required this.color,
|
@required this.color,
|
||||||
@required this.child,
|
@required this.child,
|
||||||
Key? key})
|
Key key})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
final double? width;
|
final double width;
|
||||||
final double? height;
|
final double height;
|
||||||
final void Function()? onPressed;
|
final void Function() onPressed;
|
||||||
final Widget? child;
|
final Widget child;
|
||||||
final Color? color;
|
final Color color;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class CustomTextField extends StatefulWidget {
|
class CustomTextField extends StatefulWidget {
|
||||||
final TextEditingController? textEditingController;
|
final TextEditingController textEditingController;
|
||||||
final TextInputType? textInputType;
|
final TextInputType textInputType;
|
||||||
final FocusNode? node;
|
final FocusNode node;
|
||||||
|
|
||||||
final String? hintText;
|
final String hintText;
|
||||||
final bool? isPassword;
|
final bool isPassword;
|
||||||
final IconData? icon;
|
final IconData icon;
|
||||||
final Color? iconColor;
|
final Color iconColor;
|
||||||
final Color? passIconColor;
|
final Color passIconColor;
|
||||||
|
|
||||||
final IconData? trailing;
|
final IconData trailing;
|
||||||
final void Function()? trailingCallBack;
|
final void Function() trailingCallBack;
|
||||||
|
|
||||||
final Function(String)? onChangeFtn;
|
final Function(String) onChangeFtn;
|
||||||
final void Function()? onEditComplete;
|
final void Function() onEditComplete;
|
||||||
final String? Function(String?)? validatorFtn;
|
final String Function(String) validatorFtn;
|
||||||
final Function(String)? onFieldSubmit;
|
final Function(String) onFieldSubmit;
|
||||||
final String? errorText;
|
final String errorText;
|
||||||
|
|
||||||
const CustomTextField({
|
const CustomTextField({
|
||||||
Key? key,
|
Key key,
|
||||||
@required this.textEditingController,
|
@required this.textEditingController,
|
||||||
@required this.textInputType,
|
@required this.textInputType,
|
||||||
this.trailing,
|
this.trailing,
|
||||||
|
@ -3,14 +3,14 @@ import 'package:simplex_chat/constants.dart';
|
|||||||
|
|
||||||
class MessageBubble extends StatefulWidget {
|
class MessageBubble extends StatefulWidget {
|
||||||
const MessageBubble({
|
const MessageBubble({
|
||||||
Key? key,
|
Key key,
|
||||||
this.sender,
|
this.sender,
|
||||||
this.text,
|
this.text,
|
||||||
this.isUser,
|
this.isUser,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
final String? sender;
|
final String sender;
|
||||||
final String? text;
|
final String text;
|
||||||
final bool? isUser;
|
final bool isUser;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_MessageBubbleState createState() => _MessageBubbleState();
|
_MessageBubbleState createState() => _MessageBubbleState();
|
||||||
@ -23,15 +23,15 @@ class _MessageBubbleState extends State<MessageBubble> {
|
|||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment:
|
crossAxisAlignment:
|
||||||
widget.isUser! ? CrossAxisAlignment.end : CrossAxisAlignment.start,
|
widget.isUser ? CrossAxisAlignment.end : CrossAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Text(
|
||||||
widget.sender!,
|
widget.sender,
|
||||||
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 2.0),
|
const SizedBox(height: 2.0),
|
||||||
Material(
|
Material(
|
||||||
borderRadius: widget.isUser!
|
borderRadius: widget.isUser
|
||||||
? const BorderRadius.only(
|
? const BorderRadius.only(
|
||||||
topLeft: Radius.circular(10),
|
topLeft: Radius.circular(10),
|
||||||
bottomLeft: Radius.circular(10),
|
bottomLeft: Radius.circular(10),
|
||||||
@ -41,11 +41,11 @@ class _MessageBubbleState extends State<MessageBubble> {
|
|||||||
bottomLeft: Radius.circular(10),
|
bottomLeft: Radius.circular(10),
|
||||||
bottomRight: Radius.circular(10)),
|
bottomRight: Radius.circular(10)),
|
||||||
elevation: 1.0,
|
elevation: 1.0,
|
||||||
color: widget.isUser! ? Colors.teal : kPrimaryColor,
|
color: widget.isUser ? Colors.teal : kPrimaryColor,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
||||||
child: Text(
|
child: Text(
|
||||||
widget.text!,
|
widget.text,
|
||||||
style: const TextStyle(fontSize: 15, color: Colors.white),
|
style: const TextStyle(fontSize: 15, color: Colors.white),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
version: 1.0.0+1
|
version: 1.0.0+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.12.0 <3.0.0"
|
sdk: ">=2.10.0 <3.0.0"
|
||||||
|
|
||||||
# Dependencies specify other packages that your package needs in order to work.
|
# Dependencies specify other packages that your package needs in order to work.
|
||||||
# To automatically upgrade your package dependencies to the latest versions
|
# To automatically upgrade your package dependencies to the latest versions
|
||||||
|
Loading…
Reference in New Issue
Block a user