diff --git a/Backend/Api/Routes.go b/Backend/Api/Routes.go index 6c6e2a4..10d47ef 100644 --- a/Backend/Api/Routes.go +++ b/Backend/Api/Routes.go @@ -80,6 +80,7 @@ func InitAPIEndpoints(router *mux.Router) { authAPI.HandleFunc("/conversations", Messages.UpdateConversation).Methods("PUT") authAPI.HandleFunc("/conversations/{detailID}/image", Messages.AddConversationImage).Methods("POST") authAPI.HandleFunc("/conversations/{detailID}/message_expiry", Messages.ChangeConversationMessageExpiry).Methods("POST") + authAPI.HandleFunc("/conversations/{detailID}/users/{conversationUser}", Messages.ChangeConversationMessageExpiry).Methods("POST") authAPI.HandleFunc("/message", Messages.CreateMessage).Methods("POST") authAPI.HandleFunc("/messages/{associationKey}", Messages.Messages).Methods("GET") diff --git a/Backend/Models/Conversations.go b/Backend/Models/Conversations.go index 2d048fc..8e98e2d 100644 --- a/Backend/Models/Conversations.go +++ b/Backend/Models/Conversations.go @@ -21,7 +21,7 @@ type ConversationDetail struct { AdminSendMessages string ` json:"admin_send_messages"` // Stored encrypted } -// ConversationDetailUser all users associated with a customer +// ConversationDetailUser all users associated with a conversation type ConversationDetailUser struct { Base ConversationDetailID uuid.UUID `gorm:"not null" json:"conversation_detail_id"` diff --git a/Backend/dev.sh b/Backend/dev.sh index 8b41296..7c1709a 100644 --- a/Backend/dev.sh +++ b/Backend/dev.sh @@ -3,6 +3,6 @@ while true; do go build main.go ./main & PID=$! - inotifywait -r -e modify . + inotifywait --exclude 'attachments|/\..+' -r -e modify . kill $PID done diff --git a/README.md b/README.md index d8ecf2b..711935b 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ Encrypted messaging app ## TODO -- Fix friends list search - Add friends profile picture - Add conversation pagination - Add message pagination diff --git a/mobile/ios/Runner.xcodeproj/project.pbxproj b/mobile/ios/Runner.xcodeproj/project.pbxproj index 5696b06..a3f5813 100644 --- a/mobile/ios/Runner.xcodeproj/project.pbxproj +++ b/mobile/ios/Runner.xcodeproj/project.pbxproj @@ -139,7 +139,7 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 1015E9199730C97F537825AC /* [CP] Embed Pods Frameworks */, + 68A0E21713AF256096EFD1B0 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -198,36 +198,36 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 1015E9199730C97F537825AC /* [CP] Embed Pods Frameworks */ = { + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + inputPaths = ( ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + name = "Thin Binary"; + outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + 68A0E21713AF256096EFD1B0 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); - inputPaths = ( + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "Thin Binary"; - outputPaths = ( + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; }; 90DE9D5E1F568436E776C753 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; diff --git a/mobile/lib/components/custom_circle_avatar.dart b/mobile/lib/components/custom_circle_avatar.dart index 1680fec..aa9d459 100644 --- a/mobile/lib/components/custom_circle_avatar.dart +++ b/mobile/lib/components/custom_circle_avatar.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:path/path.dart'; enum AvatarTypes { initials, @@ -24,7 +25,7 @@ class CustomCircleAvatar extends StatelessWidget { this.radius = 20, }) : super(key: key); - Widget avatar() { + Widget avatar(BuildContext context) { AvatarTypes? type; if (icon != null) { @@ -45,17 +46,17 @@ class CustomCircleAvatar extends StatelessWidget { if (type == AvatarTypes.initials) { return CircleAvatar( - backgroundColor: Colors.grey[300], - child: Text(initials!), + backgroundColor: Theme.of(context).colorScheme.tertiary, radius: radius, + child: Text(initials!), ); } if (type == AvatarTypes.icon) { return CircleAvatar( - backgroundColor: Colors.grey[300], - child: icon, + backgroundColor: Theme.of(context).colorScheme.tertiary, radius: radius, + child: icon, ); } @@ -106,7 +107,7 @@ class CustomCircleAvatar extends StatelessWidget { Widget build(BuildContext context) { return Stack( children: [ - avatar(), + avatar(context), editIcon(context), ] ); diff --git a/mobile/lib/components/custom_title_bar.dart b/mobile/lib/components/custom_title_bar.dart index 45cd96b..4e0cb52 100644 --- a/mobile/lib/components/custom_title_bar.dart +++ b/mobile/lib/components/custom_title_bar.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; @immutable class CustomTitleBar extends StatelessWidget with PreferredSizeWidget { @@ -8,6 +9,8 @@ class CustomTitleBar extends StatelessWidget with PreferredSizeWidget { required this.showBack, this.rightHandButton, this.backgroundColor, + this.forgroundColor, + this.iconColor, this.beforeBack, }) : super(key: key); @@ -15,6 +18,8 @@ class CustomTitleBar extends StatelessWidget with PreferredSizeWidget { final bool showBack; final IconButton? rightHandButton; final Color? backgroundColor; + final Color? forgroundColor; + final Color? iconColor; final Future Function()? beforeBack; @override @@ -23,39 +28,45 @@ class CustomTitleBar extends StatelessWidget with PreferredSizeWidget { @override Widget build(BuildContext context) { return AppBar( - elevation: 0, - automaticallyImplyLeading: false, - backgroundColor: - backgroundColor != null ? - backgroundColor! : - Theme.of(context).appBarTheme.backgroundColor, - flexibleSpace: SafeArea( - child: Container( - padding: const EdgeInsets.only(right: 16), - child: Row( - children: [ - showBack ? - _backButton(context) : - const SizedBox.shrink(), - showBack ? - const SizedBox(width: 2,) : - const SizedBox(width: 15), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - title, - ], - ), + elevation: 0, + automaticallyImplyLeading: false, + backgroundColor: + backgroundColor != null ? + backgroundColor! : + Theme.of(context).appBarTheme.backgroundColor, + foregroundColor: forgroundColor != null ? + forgroundColor! : + Theme.of(context).appBarTheme.foregroundColor, + systemOverlayStyle: const SystemUiOverlayStyle( + statusBarColor: Colors.white, + ), + flexibleSpace: SafeArea( + child: Container( + padding: const EdgeInsets.only(right: 16), + child: Row( + children: [ + showBack ? + _backButton(context) : + const SizedBox.shrink(), + showBack ? + const SizedBox(width: 2,) : + const SizedBox(width: 15), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + title, + ], ), - rightHandButton != null ? - rightHandButton! : - const SizedBox.shrink(), - ], - ), + ), + rightHandButton != null ? + rightHandButton! : + const SizedBox.shrink(), + ], ), ), + ), ); } @@ -69,9 +80,11 @@ class CustomTitleBar extends StatelessWidget with PreferredSizeWidget { Navigator.pop(context); }, icon: Icon( - Icons.arrow_back, - color: Theme.of(context).appBarTheme.iconTheme?.color, - ), + Icons.arrow_back, + color: iconColor != null ? + iconColor! : + Theme.of(context).appBarTheme.iconTheme?.color, + ), ); } } diff --git a/mobile/lib/components/file_picker.dart b/mobile/lib/components/file_picker.dart index 7160e0d..1217618 100644 --- a/mobile/lib/components/file_picker.dart +++ b/mobile/lib/components/file_picker.dart @@ -97,6 +97,7 @@ class FilePicker extends StatelessWidget { child: Icon( icon, size: 40, + color: Colors.white, ), ), ), diff --git a/mobile/lib/components/view_image.dart b/mobile/lib/components/view_image.dart index 2fe3fcf..79e7d88 100644 --- a/mobile/lib/components/view_image.dart +++ b/mobile/lib/components/view_image.dart @@ -18,6 +18,8 @@ class ViewImage extends StatelessWidget { title: Text(''), showBack: true, backgroundColor: Colors.black, + forgroundColor: Colors.white, + iconColor: Colors.white, ), body: Center( child: InteractiveViewer( diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index e8bfd8e..a63a1b6 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -1,5 +1,6 @@ import 'package:Envelope/models/my_profile.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import '/views/main/home.dart'; import '/views/authentication/unauthenticated_landing.dart'; @@ -31,78 +32,143 @@ class MyApp extends StatelessWidget { '/signup': (context) => const Signup(), }, home: const Scaffold( - body: SafeArea( - child: Home(), - ) - ), + body: SafeArea( + child: Home(), + ) + ), theme: ThemeData( + brightness: Brightness.light, + primaryColor: const Color(0xff014bff), + backgroundColor: Colors.grey[300], + scaffoldBackgroundColor: Colors.grey.shade100, + disabledColor: Colors.grey[700], + hintColor: Colors.grey.shade700, + + colorScheme: ColorScheme( brightness: Brightness.light, - primaryColor: Colors.red, - appBarTheme: const AppBarTheme( - backgroundColor: Colors.cyan, - elevation: 0, + primary: const Color(0xff014bff), + onPrimary: Colors.white, + secondary: const Color(0xff1a6dff), + onSecondary: Colors.black, + tertiary: const Color(0xff3490ff), + onTertiary: Colors.black, + error: Colors.red, + onError: Colors.white, + background: Colors.grey.shade300, + onBackground: Colors.black, + surface: Colors.grey.shade100, + onSurface: Colors.black, + ), + + appBarTheme: AppBarTheme( + color: Colors.grey.shade100, + foregroundColor: Colors.white, + iconTheme: const IconThemeData( + color: Colors.black, + ), + toolbarTextStyle: const TextStyle( + color: Colors.black, + ), + + systemOverlayStyle: const SystemUiOverlayStyle( + statusBarColor: Colors.black, + + statusBarIconBrightness: Brightness.light, + statusBarBrightness: Brightness.light, + ) + ), + + iconTheme: const IconThemeData(color: Colors.black), + + inputDecorationTheme: InputDecorationTheme( + filled: true, + fillColor: Colors.white, + labelStyle: const TextStyle( + color: Colors.black, + fontSize: 30, ), - inputDecorationTheme: const InputDecorationTheme( - labelStyle: TextStyle( - color: Colors.white, - fontSize: 30, - ), - filled: false, + hintStyle: TextStyle( + color: Colors.grey.shade600, ), + iconColor: Colors.grey.shade500, + contentPadding: const EdgeInsets.all(8), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(15), + borderSide: const BorderSide( + color: Colors.transparent, + ) + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(15), + borderSide: const BorderSide( + color: Colors.transparent, + ) + ), + ), ), - darkTheme: ThemeData( + darkTheme: ThemeData( brightness: Brightness.dark, - primaryColor: Colors.orange.shade900, + primaryColor: const Color(0xffff4a27), backgroundColor: Colors.grey.shade800, scaffoldBackgroundColor: Colors.grey[850], disabledColor: Colors.grey[400], + hintColor: Colors.grey.shade400, + colorScheme: ColorScheme( - brightness: Brightness.dark, - primary: Colors.orange.shade900, - onPrimary: Colors.white, - secondary: Colors.orange.shade900, - onSecondary: Colors.white, - tertiary: Colors.grey.shade500, - onTertiary: Colors.black, - error: Colors.red, - onError: Colors.white, - background: Colors.grey.shade900, - onBackground: Colors.white, - surface: Colors.grey.shade700, - onSurface: Colors.white, + brightness: Brightness.dark, + primary: const Color(0xffff4a27), + onPrimary: Colors.white, + secondary: const Color(0xffff5f3a), + onSecondary: Colors.white, + tertiary: const Color(0xffff7950), + onTertiary: Colors.black, + error: Colors.red, + onError: Colors.white, + background: Colors.grey.shade900, + onBackground: Colors.white, + surface: Colors.grey.shade700, + onSurface: Colors.white, + ), + + appBarTheme: AppBarTheme( + color: Colors.grey.shade800, + iconTheme: IconThemeData( + color: Colors.grey.shade400 ), - hintColor: Colors.grey.shade500, - inputDecorationTheme: InputDecorationTheme( - filled: true, - fillColor: Colors.grey.shade800, - hintStyle: TextStyle( - color: Colors.grey.shade500, - ), - iconColor: Colors.grey.shade500, - contentPadding: const EdgeInsets.all(8), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(15), - borderSide: const BorderSide( - color: Colors.transparent, - ) - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(15), - borderSide: const BorderSide( - color: Colors.transparent, - ) - ), + toolbarTextStyle: TextStyle( + color: Colors.grey.shade400 + ), + systemOverlayStyle: const SystemUiOverlayStyle( + statusBarColor: Colors.black, + + statusBarIconBrightness: Brightness.dark, + statusBarBrightness: Brightness.dark, + ) + ), + + iconTheme: const IconThemeData(color: Colors.white), + inputDecorationTheme: InputDecorationTheme( + filled: true, + fillColor: Colors.grey.shade800, + hintStyle: TextStyle( + color: Colors.grey.shade500, ), - appBarTheme: AppBarTheme( - color: Colors.grey.shade800, - iconTheme: IconThemeData( - color: Colors.grey.shade400 - ), - toolbarTextStyle: TextStyle( - color: Colors.grey.shade400 - ), + iconColor: Colors.grey.shade500, + contentPadding: const EdgeInsets.all(8), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(15), + borderSide: const BorderSide( + color: Colors.transparent, + ) + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(15), + borderSide: const BorderSide( + color: Colors.transparent, + ) ), + ), ), ); } diff --git a/mobile/lib/utils/storage/conversations.dart b/mobile/lib/utils/storage/conversations.dart index 3165332..096b9ba 100644 --- a/mobile/lib/utils/storage/conversations.dart +++ b/mobile/lib/utils/storage/conversations.dart @@ -181,7 +181,7 @@ Future updateConversations() async { } -Future uploadConversation(Conversation conversation, BuildContext context) async { +Future uploadConversation(Conversation conversation) async { String sessionCookie = await getSessionCookie(); Map conversationJson = await conversation.payloadJson(); @@ -196,7 +196,7 @@ Future uploadConversation(Conversation conversation, BuildContext context) ); if (resp.statusCode != 204) { - showMessage('Failed to create conversation', context); + throw Exception('Failed to create conversation'); } } diff --git a/mobile/lib/views/authentication/login.dart b/mobile/lib/views/authentication/login.dart index 8835080..3b38289 100644 --- a/mobile/lib/views/authentication/login.dart +++ b/mobile/lib/views/authentication/login.dart @@ -102,8 +102,7 @@ class _LoginWidgetState extends State { ); final ButtonStyle buttonStyle = ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.surface, - foregroundColor: Theme.of(context).colorScheme.onSurface, + backgroundColor: Theme.of(context).colorScheme.tertiary, minimumSize: const Size.fromHeight(50), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10), textStyle: TextStyle( diff --git a/mobile/lib/views/authentication/signup.dart b/mobile/lib/views/authentication/signup.dart index 2a190e0..effb89e 100644 --- a/mobile/lib/views/authentication/signup.dart +++ b/mobile/lib/views/authentication/signup.dart @@ -85,15 +85,14 @@ class _SignupWidgetState extends State { Widget build(BuildContext context) { final ButtonStyle buttonStyle = ElevatedButton.styleFrom( - primary: Theme.of(context).colorScheme.surface, - onPrimary: Theme.of(context).colorScheme.onSurface, - minimumSize: const Size.fromHeight(50), - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10), - textStyle: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Theme.of(context).colorScheme.error, - ), + backgroundColor: Theme.of(context).colorScheme.tertiary, + minimumSize: const Size.fromHeight(50), + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10), + textStyle: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.error, + ), ); return Center( @@ -213,7 +212,7 @@ class _SignupWidgetState extends State { Widget serverUrl() { if (!showUrlInput) { - return + return Padding( padding: const EdgeInsets.only(top: 0, bottom: 10), child: Row( @@ -221,9 +220,9 @@ class _SignupWidgetState extends State { SizedBox( height: 10, child: IconButton( - onPressed: () { + onPressed: () { setState(() { - showUrlInput = true; + showUrlInput = true; }); }, icon: Icon( @@ -276,7 +275,7 @@ class _SignupWidgetState extends State { var rsaPrivPem = CryptoUtils.encodeRSAPrivateKeyToPem(keyPair.privateKey); String encRsaPriv = AesHelper.aesEncrypt( - _passwordController.text, + _passwordController.text, Uint8List.fromList(rsaPrivPem.codeUnits), ); diff --git a/mobile/lib/views/authentication/unauthenticated_landing.dart b/mobile/lib/views/authentication/unauthenticated_landing.dart index 2dcb15f..800f05b 100644 --- a/mobile/lib/views/authentication/unauthenticated_landing.dart +++ b/mobile/lib/views/authentication/unauthenticated_landing.dart @@ -14,8 +14,7 @@ class _UnauthenticatedLandingWidgetState extends State { Navigator.of(context).push( MaterialPageRoute(builder: (context) => const Login()), ), }, style: buttonStyle, + child: const Text('Login'), ), const SizedBox(height: 20), ElevatedButton( - child: const Text('Sign Up'), onPressed: () => { Navigator.of(context).push( MaterialPageRoute(builder: (context) => const Signup()), ), }, style: buttonStyle, + child: const Text('Sign Up'), ), const SizedBox(height: 50), ] diff --git a/mobile/lib/views/main/conversation/detail.dart b/mobile/lib/views/main/conversation/detail.dart index 68b89b5..b46a34f 100644 --- a/mobile/lib/views/main/conversation/detail.dart +++ b/mobile/lib/views/main/conversation/detail.dart @@ -269,12 +269,12 @@ class _ConversationDetailState extends State { selectedImages = []; }); }, + backgroundColor: Theme.of(context).primaryColor, child: Icon( Icons.send, color: Theme.of(context).colorScheme.onPrimary, size: 22 ), - backgroundColor: Theme.of(context).primaryColor, ), ), ), diff --git a/mobile/lib/views/main/conversation/list.dart b/mobile/lib/views/main/conversation/list.dart index be4b494..7c1b6b2 100644 --- a/mobile/lib/views/main/conversation/list.dart +++ b/mobile/lib/views/main/conversation/list.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:Envelope/components/custom_title_bar.dart'; +import 'package:Envelope/components/flash_message.dart'; import 'package:Envelope/models/friends.dart'; import 'package:Envelope/utils/storage/conversations.dart'; import 'package:flutter/material.dart'; @@ -79,10 +80,13 @@ class _ConversationListState extends State { false, ); - uploadConversation(conversation, context); + uploadConversation(conversation) + .catchError((dynamic) { + showMessage('Failed to create conversation', context); + }); Navigator.of(context).popUntil((route) => route.isFirst); - Navigator.push(context, MaterialPageRoute(builder: (context){ + Navigator.push(context, MaterialPageRoute(builder: (context) { return ConversationDetail( conversation: conversation, ); @@ -95,7 +99,11 @@ class _ConversationListState extends State { ).then(onGoBack); }, backgroundColor: Theme.of(context).colorScheme.primary, - child: const Icon(Icons.add, size: 30), + child: Icon( + Icons.add, + size: 30, + color: Theme.of(context).colorScheme.onPrimary, + ), ), ), ); diff --git a/mobile/lib/views/main/conversation/message.dart b/mobile/lib/views/main/conversation/message.dart index 5bdc982..f83b4ce 100644 --- a/mobile/lib/views/main/conversation/message.dart +++ b/mobile/lib/views/main/conversation/message.dart @@ -78,10 +78,10 @@ class _ConversationMessageState extends State { padding: const EdgeInsets.only(left: 14,right: 14,top: 0,bottom: 0), child: Align( alignment: ( - widget.message.senderId == widget.profile.id ? - Alignment.topRight : - Alignment.topLeft - ), + widget.message.senderId == widget.profile.id ? + Alignment.topRight : + Alignment.topLeft + ), child: Column( crossAxisAlignment: widget.message.senderId == widget.profile.id ? CrossAxisAlignment.end : @@ -117,7 +117,7 @@ class _ConversationMessageState extends State { TextAlign.right, style: TextStyle( fontSize: 12, - color: Colors.grey[500], + color: Theme.of(context).hintColor, ), ), ], @@ -133,6 +133,10 @@ class _ConversationMessageState extends State { } void _showCustomMenu() { + if (menuItems.isEmpty) { + return; + } + final Size overlay = MediaQuery.of(context).size; int addVerticalOffset = 75 * menuItems.length; @@ -142,8 +146,8 @@ class _ConversationMessageState extends State { context: context, items: menuItems, position: RelativeRect.fromRect( - Offset(_tapPosition!.dx, (_tapPosition!.dy - addVerticalOffset)) & const Size(40, 40), - Offset.zero & overlay + Offset(_tapPosition!.dx, (_tapPosition!.dy - addVerticalOffset)) & const Size(40, 40), + Offset.zero & overlay ) ) .then((String? delta) async { @@ -213,7 +217,7 @@ class _ConversationMessageState extends State { widget.message.senderUsername, style: TextStyle( fontSize: 12, - color: Colors.grey[300], + color: Theme.of(context).hintColor, ), ); } diff --git a/mobile/lib/views/main/conversation/settings.dart b/mobile/lib/views/main/conversation/settings.dart index 3aa41f9..ce29174 100644 --- a/mobile/lib/views/main/conversation/settings.dart +++ b/mobile/lib/views/main/conversation/settings.dart @@ -46,7 +46,7 @@ class _ConversationSettingsState extends State { return Scaffold( appBar: CustomTitleBar( title: Text( - widget.conversation.name + ' Settings', + '${widget.conversation.name} Settings', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, @@ -176,7 +176,8 @@ class _ConversationSettingsState extends State { style: TextStyle(fontSize: 16) ), icon: const Icon(Icons.exit_to_app), - style: const ButtonStyle( + style: ButtonStyle( + foregroundColor: MaterialStateProperty.all(Theme.of(context).colorScheme.error), alignment: Alignment.centerLeft, ), onPressed: () { @@ -328,7 +329,7 @@ return Theme.of(context).colorScheme.onBackground; user: users[i], isAdmin: widget.conversation.admin, twoUser: widget.conversation.twoUser, - profile: profile!, // TODO: Fix this + profile: profile!, ); } ); diff --git a/mobile/lib/views/main/friend/list.dart b/mobile/lib/views/main/friend/list.dart index 95dab97..53b7244 100644 --- a/mobile/lib/views/main/friend/list.dart +++ b/mobile/lib/views/main/friend/list.dart @@ -71,7 +71,11 @@ class _FriendListState extends State { floatingActionButton: Padding( padding: const EdgeInsets.only(right: 10, bottom: 10), child: ExpandableFab( - icon: const Icon(Icons.add, size: 30), + icon: Icon( + Icons.add, + size: 30, + color: Theme.of(context).colorScheme.onPrimary, + ), distance: 90.0, children: [ ActionButton( @@ -163,7 +167,7 @@ class _FriendListState extends State { heading, style: TextStyle( fontSize: 16, - color: Theme.of(context).colorScheme.tertiary, + color: Theme.of(context).hintColor, ), ), ) diff --git a/mobile/lib/views/main/friend/list_item.dart b/mobile/lib/views/main/friend/list_item.dart index dc411ba..bb83f6e 100644 --- a/mobile/lib/views/main/friend/list_item.dart +++ b/mobile/lib/views/main/friend/list_item.dart @@ -1,7 +1,9 @@ import 'package:Envelope/components/custom_circle_avatar.dart'; +import 'package:Envelope/components/flash_message.dart'; import 'package:Envelope/models/conversations.dart'; import 'package:Envelope/models/friends.dart'; import 'package:Envelope/utils/storage/conversations.dart'; +import 'package:Envelope/utils/storage/messages.dart'; import 'package:Envelope/utils/strings.dart'; import 'package:Envelope/views/main/conversation/detail.dart'; import 'package:flutter/material.dart'; @@ -67,7 +69,10 @@ class _FriendListItemState extends State { true, ); - uploadConversation(conversation, context); + uploadConversation(conversation) + .catchError((dynamic d) async { + showMessage('Failed to create conversation', context); + }); Navigator.push(context, MaterialPageRoute(builder: (context){ return ConversationDetail( diff --git a/mobile/lib/views/main/home.dart b/mobile/lib/views/main/home.dart index 58e9f8e..157c25b 100644 --- a/mobile/lib/views/main/home.dart +++ b/mobile/lib/views/main/home.dart @@ -49,13 +49,17 @@ class _HomeState extends State { onWillPop: () async => false, child: isLoading ? loading() : Scaffold( body: _widgetOptions.elementAt(_selectedIndex), - bottomNavigationBar: isLoading ? const SizedBox.shrink() : BottomNavigationBar( + bottomNavigationBar: isLoading ? + const SizedBox.shrink() : + BottomNavigationBar( currentIndex: _selectedIndex, onTap: _onItemTapped, selectedItemColor: Theme.of(context).primaryColor, unselectedItemColor: Theme.of(context).hintColor, selectedLabelStyle: const TextStyle(fontWeight: FontWeight.w600), unselectedLabelStyle: const TextStyle(fontWeight: FontWeight.w600), + backgroundColor: Colors.transparent, + elevation: 0, type: BottomNavigationBarType.fixed, items: const [ BottomNavigationBarItem( diff --git a/mobile/lib/views/main/profile/profile.dart b/mobile/lib/views/main/profile/profile.dart index d4e91c5..2e00671 100644 --- a/mobile/lib/views/main/profile/profile.dart +++ b/mobile/lib/views/main/profile/profile.dart @@ -190,12 +190,13 @@ class _ProfileState extends State { children: [ TextButton.icon( label: const Text( - 'Logout', - style: TextStyle(fontSize: 16) + 'Logout', + style: TextStyle(fontSize: 16) ), icon: const Icon(Icons.exit_to_app), - style: const ButtonStyle( - alignment: Alignment.centerLeft, + style: ButtonStyle( + foregroundColor: MaterialStateProperty.all(Theme.of(context).colorScheme.error), + alignment: Alignment.centerLeft, ), onPressed: () { deleteDb(); @@ -205,12 +206,13 @@ class _ProfileState extends State { ), isTesting ? TextButton.icon( label: const Text( - 'Delete Database', - style: TextStyle(fontSize: 16) + 'Delete Database', + style: TextStyle(fontSize: 16) ), icon: const Icon(Icons.delete_forever), - style: const ButtonStyle( - alignment: Alignment.centerLeft, + style: ButtonStyle( + foregroundColor: MaterialStateProperty.all(Theme.of(context).colorScheme.error), + alignment: Alignment.centerLeft, ), onPressed: () { deleteDb(); @@ -345,7 +347,7 @@ class _ProfileState extends State { Padding( padding: const EdgeInsets.all(20), child: QrImage( - backgroundColor: Theme.of(context).colorScheme.primary, + backgroundColor: Theme.of(context).colorScheme.tertiary, data: payload, version: QrVersions.auto, gapless: true, diff --git a/mobile/pubspec.lock b/mobile/pubspec.lock index 824f474..9567b65 100644 --- a/mobile/pubspec.lock +++ b/mobile/pubspec.lock @@ -7,7 +7,7 @@ packages: name: asn1lib url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" async: dependency: transitive description: @@ -49,14 +49,14 @@ packages: name: convert url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.1.1" cross_file: dependency: transitive description: name: cross_file url: "https://pub.dartlang.org" source: hosted - version: "0.3.3+1" + version: "0.3.3+2" crypto: dependency: transitive description: @@ -70,7 +70,7 @@ packages: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.5" fake_async: dependency: transitive description: @@ -84,14 +84,14 @@ packages: name: ffi url: "https://pub.dartlang.org" source: hosted - version: "1.2.1" + version: "2.0.1" file: dependency: transitive description: name: file url: "https://pub.dartlang.org" source: hosted - version: "6.1.2" + version: "6.1.4" flutter: dependency: "direct main" description: flutter @@ -110,7 +110,7 @@ packages: name: flutter_lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.1" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -134,49 +134,49 @@ packages: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.13.4" + version: "0.13.5" http_parser: dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "4.0.1" + version: "4.0.2" image_picker: dependency: "direct main" description: name: image_picker url: "https://pub.dartlang.org" source: hosted - version: "0.8.5+3" + version: "0.8.6" image_picker_android: dependency: transitive description: name: image_picker_android url: "https://pub.dartlang.org" source: hosted - version: "0.8.5+2" + version: "0.8.5+3" image_picker_for_web: dependency: transitive description: name: image_picker_for_web url: "https://pub.dartlang.org" source: hosted - version: "2.1.8" + version: "2.1.10" image_picker_ios: dependency: transitive description: name: image_picker_ios url: "https://pub.dartlang.org" source: hosted - version: "0.8.5+6" + version: "0.8.6+1" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.6.1" + version: "2.6.2" intl: dependency: "direct main" description: @@ -197,7 +197,7 @@ packages: name: lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "2.0.0" matcher: dependency: transitive description: @@ -260,7 +260,7 @@ packages: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.6" + version: "2.1.7" path_provider_macos: dependency: transitive description: @@ -274,14 +274,14 @@ packages: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "2.0.5" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.6" + version: "2.1.3" platform: dependency: transitive description: @@ -295,14 +295,14 @@ packages: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.3" pointycastle: dependency: "direct main" description: name: pointycastle url: "https://pub.dartlang.org" source: hosted - version: "3.5.2" + version: "3.6.2" process: dependency: transitive description: @@ -344,7 +344,7 @@ packages: name: shared_preferences_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.12" + version: "2.0.14" shared_preferences_ios: dependency: transitive description: @@ -372,7 +372,7 @@ packages: name: shared_preferences_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" shared_preferences_web: dependency: transitive description: @@ -412,14 +412,14 @@ packages: name: sqflite url: "https://pub.dartlang.org" source: hosted - version: "2.0.2+1" + version: "2.1.0+1" sqflite_common: dependency: transitive description: name: sqflite_common url: "https://pub.dartlang.org" source: hosted - version: "2.2.1+1" + version: "2.3.0" stack_trace: dependency: transitive description: @@ -447,7 +447,7 @@ packages: name: synchronized url: "https://pub.dartlang.org" source: hosted - version: "3.0.0+2" + version: "3.0.0+3" term_glyph: dependency: transitive description: @@ -468,7 +468,7 @@ packages: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" uuid: dependency: "direct main" description: @@ -489,14 +489,14 @@ packages: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "2.5.2" + version: "3.0.1" xdg_directories: dependency: transitive description: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.2.0+1" + version: "0.2.0+2" sdks: - dart: ">=2.17.0 <3.0.0" - flutter: ">=2.8.1" + dart: ">=2.18.0 <3.0.0" + flutter: ">=3.3.0-0" diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index 983b336..dcb8af8 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -32,7 +32,7 @@ dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^1.0.0 + flutter_lints: ^2.0.1 flutter: uses-material-design: true