diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index 592ceee..ec97fc6 100644 --- a/ios/Flutter/Debug.xcconfig +++ b/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig index 592ceee..c4855bf 100644 --- a/ios/Flutter/Release.xcconfig +++ b/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..88359b2 --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,41 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '11.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 0000000..dcf9b43 --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,23 @@ +PODS: + - Flutter (1.0.0) + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - Flutter (from `Flutter`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`) + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + shared_preferences_foundation: + :path: ".symlinks/plugins/shared_preferences_foundation/ios" + +SPEC CHECKSUMS: + Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472 + +PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 + +COCOAPODS: 1.12.0 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 61b0029..d79a4d5 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + E3576D595173CFA1AEA7F520 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 715425FFAD080BA1FA449D37 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -32,9 +33,11 @@ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 715425FFAD080BA1FA449D37 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 7B4458CAE75A20D2D1C2C250 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -42,6 +45,8 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + AD276E8EF87F3AC6F2EB097E /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + B5AAD9DD91BFEBB3D4EC81C3 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -49,12 +54,32 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + E3576D595173CFA1AEA7F520 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 364BC066090A5558A18CD625 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 715425FFAD080BA1FA449D37 /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 4727C5B36985EDF4613ED581 /* Pods */ = { + isa = PBXGroup; + children = ( + AD276E8EF87F3AC6F2EB097E /* Pods-Runner.debug.xcconfig */, + B5AAD9DD91BFEBB3D4EC81C3 /* Pods-Runner.release.xcconfig */, + 7B4458CAE75A20D2D1C2C250 /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -72,6 +97,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, + 4727C5B36985EDF4613ED581 /* Pods */, + 364BC066090A5558A18CD625 /* Frameworks */, ); sourceTree = ""; }; @@ -105,12 +132,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + E4A27509ABF1F224697981E0 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ACACE73FA41CF1EE9D2A04C8 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -199,6 +228,45 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + ACACE73FA41CF1EE9D2A04C8 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + 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 = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + E4A27509ABF1F224697981E0 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/lib/main.dart b/lib/main.dart index 0135661..ab8489e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,10 @@ import 'package:flutter/material.dart'; import 'package:veil/src/app.dart'; - -void main() { +import 'package:flutter_dotenv/flutter_dotenv.dart'; +void main() async { + print('Loading Envs'); + await dotenv.load(); + + print(dotenv.env); runApp(const App()); } diff --git a/lib/src/api/http_client.dart b/lib/src/api/http_client.dart new file mode 100644 index 0000000..0195189 --- /dev/null +++ b/lib/src/api/http_client.dart @@ -0,0 +1,29 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:http/http.dart' as http; + +const timeoutSec = 5; +const Map defaultHeaders = { + 'Content-Type': 'application/json; charset=UTF-8', + 'version': "1.0" +}; + +Future post(String url, + [Map body = const {}, Map headers = defaultHeaders]) async { + try { + final res = await http + .post( + Uri.parse(url), + headers: headers, + body: jsonEncode(body), + ) + .timeout(const Duration(seconds: timeoutSec)); + return res; + } on TimeoutException catch (e) { + return http.Response(e.toString(), 504); + } on Exception catch (e) { + // log error + return http.Response(e.toString(), 500); + } +} diff --git a/lib/src/app.dart b/lib/src/app.dart index 2418878..c0c33f5 100644 --- a/lib/src/app.dart +++ b/lib/src/app.dart @@ -1,89 +1,94 @@ - import 'package:flutter/material.dart'; +import 'package:veil/src/pages/profile.dart'; +import 'package:veil/src/pages/register.dart'; +import 'package:veil/utils/auth/auth.dart' as auth; class App extends StatelessWidget { - const App({super.key}); + const App({Key? key}); - // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Veil', theme: ThemeData( - // This is the theme of your application. - // - // Try running your application with "flutter run". You'll see the - // application has a blue toolbar. Then, without quitting the app, try - // changing the primarySwatch below to Colors.green and then invoke - // "hot reload" (press "r" in the console where you ran "flutter run", - // or simply save your changes to "hot reload" in a Flutter IDE). - // Notice that the counter didn't reset back to zero; the application - // is not restarted. - primarySwatch: Colors.indigo, + primarySwatch: Colors.teal, + scaffoldBackgroundColor: Color.fromARGB(255, 201, 192, 236), ), - home: const MyHomePage(title: 'Veil'), + home: const HomePage(title: 'Veil'), ); } } -class MyHomePage extends StatefulWidget { - const MyHomePage({super.key, required this.title}); - - // This widget is the home page of your application. It is stateful, meaning - // that it has a State object (defined below) that contains fields that affect - // how it looks. - - // This class is the configuration for the state. It holds the values (in this - // case the title) provided by the parent (in this case the App widget) and - // used by the build method of the State. Fields in a Widget subclass are - // always marked "final". - +class HomePage extends StatefulWidget { + const HomePage({Key? key, required this.title}) : super(key: key); final String title; @override - State createState() => _MyHomePageState(); + _HomePageState createState() => _HomePageState(); } -class _MyHomePageState extends State { +class _HomePageState extends State { + bool _showRegisterScreen = false; + bool _loading = false; + bool _error = false; + + @override + void initState() { + super.initState(); + } @override Widget build(BuildContext context) { - // This method is rerun every time setState is called, for instance as done - // by the _incrementCounter method above. - // - // The Flutter framework has been optimized to make rerunning build methods - // fast, so that you can just rebuild anything that needs updating rather - // than having to individually change instances of widgets. - return Scaffold( - appBar: AppBar( - // Here we take the value from the MyHomePage object that was created by - // the App.build method, and use it to set our appbar title. - title: Text(widget.title), - ), - body: Center( - // Center is a layout widget. It takes a single child and positions it - // in the middle of the parent. - child: Column( - // Column is also a layout widget. It takes a list of children and - // arranges them vertically. By default, it sizes itself to fit its - // children horizontally, and tries to be as tall as its parent. - // - // Invoke "debug painting" (press "p" in the console, choose the - // "Toggle Debug Paint" action from the Flutter Inspector in Android - // Studio, or the "Toggle Debug Paint" command in Visual Studio Code) - // to see the wireframe for each widget. - // - // Column has various properties to control how it sizes itself and - // how it positions its children. Here we use mainAxisAlignment to - // center the children vertically; the main axis here is the vertical - // axis because Columns are vertical (the cross axis would be - // horizontal). - mainAxisAlignment: MainAxisAlignment.center, - children: [ - FilledButton.tonal(onPressed: (){}, child: const Text("Register")), - FilledButton(onPressed: (){}, child: const Text("Sign In")) - ], + if (_error) { + return const Scaffold( + body: Center( + child: Text( + 'Error connecting to services.', + style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), + ), + ), + ); + } + if (_loading) { + return const Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ); + } + if (_showRegisterScreen) { + return Scaffold( + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const RegisterPage(), + const SizedBox(height: 20), + ElevatedButton( + onPressed: () async { + try { + setState(() { + _loading = true; + }); + var storedToken = await auth.findTokenOnDevice(); + + //validate the stored token + print('found token in device(${storedToken}), validating it.'); + } + on Exception catch (_, e) { + setState(() { _loading = true; }); + } + }, + child: const Text("Login As New User!"), + ), + ], + ), ), + ); + } + return const Scaffold( + body: SafeArea( + child: UserProfilePage(), ), ); } diff --git a/lib/src/pages/chat.dart b/lib/src/pages/chat.dart new file mode 100644 index 0000000..a316cfa --- /dev/null +++ b/lib/src/pages/chat.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; +import 'package:veil/src/pages/inbox.dart'; + +class ChatPage extends StatefulWidget { + @override + _ChatPageState createState() => _ChatPageState(); +} + +class _ChatPageState extends State { + TextEditingController _textEditingController = TextEditingController(); + List messages = []; + + void _sendMessage() { + String message = _textEditingController.text.trim(); + if (message.isNotEmpty) { + setState(() { + messages.add(message); + _textEditingController.clear(); + }); + } + } + + @override + void dispose() { + _textEditingController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Chat'), + ), + body: Column( + children: [ + Expanded( + child: ListView.builder( + itemCount: messages.length, + itemBuilder: (context, index) => ChatMessageItem( + name: 'John Doe', + chatMessage: messages[index], + ), + ), + ), + Padding( + padding: EdgeInsets.all(8.0), + child: Row( + children: [ + Expanded( + child: TextField( + controller: _textEditingController, + decoration: InputDecoration( + hintText: 'Type your message...', + ), + ), + ), + SizedBox(width: 8.0), + IconButton( + icon: Icon(Icons.send), + onPressed: _sendMessage, + ), + ], + ), + ), + ], + ), + ); + } +} + +class ChatMessageItem extends StatelessWidget { + final String name; + final String chatMessage; + + const ChatMessageItem({ + required this.name, + required this.chatMessage, + }); + + @override + Widget build(BuildContext context) { + return ListTile( + leading: CircleAvatar( + backgroundImage: NetworkImage('https://i.pinimg.com/564x/cd/cb/01/cdcb01ebeef668284a58c06f5b08708e.jpg'), + ), + title: Text(name), + subtitle: Text(chatMessage), + ); + } +} diff --git a/lib/src/pages/home.dart b/lib/src/pages/home.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/src/pages/inbox.dart b/lib/src/pages/inbox.dart index e69de29..93fb374 100644 --- a/lib/src/pages/inbox.dart +++ b/lib/src/pages/inbox.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:veil/src/pages/profile.dart'; +import 'package:veil/src/pages/chat.dart'; +class InboxPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Inbox'), + ), + body: ListView( + children: [ + ChatItem(name: 'John Doe'), + ], + ), + ); + } +} + +class ChatItem extends StatelessWidget { + final String name; + + const ChatItem({required this.name}); + + @override + Widget build(BuildContext context) { + return ListTile( + leading: CircleAvatar( + child: Text(name[0]), + ), + title: Text(name), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => ChatPage()), + ); + }, + ); + } +} diff --git a/lib/src/pages/new_post_bottomsheet.dart b/lib/src/pages/new_post_bottomsheet.dart new file mode 100644 index 0000000..11a388e --- /dev/null +++ b/lib/src/pages/new_post_bottomsheet.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; + +class NewPostBottomsheet extends StatefulWidget { + @override + State createState() => _NewPostBottomsheet(); +} + +class _NewPostBottomsheet extends State { + final TextEditingController _controller = TextEditingController(); + @override + Widget build(BuildContext context) { + return Container( + height: 800, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Align( + child: Text( + "New post", + style: TextStyle(fontWeight: FontWeight.w500, fontSize: 30), + ), + ), + const SizedBox( + height: 20, + ), + const Text("What's your secret?"), + TextField( + controller: _controller, + ), + const Text("Choose background"), + Align(child: ElevatedButton(onPressed: () {}, child: const Text("Post!"))) + ], + ), + ), + ); + } +} diff --git a/lib/src/pages/post.dart b/lib/src/pages/post.dart index e69de29..3d56b2a 100644 --- a/lib/src/pages/post.dart +++ b/lib/src/pages/post.dart @@ -0,0 +1,107 @@ +import 'package:flutter/material.dart'; +import 'package:veil/src/pages/new_post_bottomsheet.dart'; +import 'package:veil/src/pages/profile.dart'; +import 'package:veil/src/pages/inbox.dart'; + +class PostPage extends StatefulWidget { + const PostPage({super.key}); + + @override + State createState() => _PostPageState(); +} + +class _PostPageState extends State + with SingleTickerProviderStateMixin { + late TabController _tabController; + + @override + void initState() { + super.initState(); + _tabController = TabController(length: 2, vsync: this); + } + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.person), + onPressed: () => Navigator.push( + context, + MaterialPageRoute(builder: (context) => const UserProfilePage()), + ), + ), + actions: [ + IconButton( + icon: const Icon(Icons.chat), + tooltip: 'Chats', + onPressed: () => Navigator.push( + context, + MaterialPageRoute(builder: (context) => InboxPage()), + ), + ), + ], + title: const Text('Posts'), + bottom: TabBar( + controller: _tabController, + tabs: const [ + Tab(text: 'Popular Posts'), + Tab(text: 'Nearby Posts'), + ], + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: () { + showModalBottomSheet(context: context, builder: bottomSheetBuilder); + }, + backgroundColor: Colors.green, + child: const Icon(Icons.add), + ), + body: TabBarView( + controller: _tabController, + children: [ + GridView.builder( + padding: const EdgeInsets.all(8.0), + itemCount: 20, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 8.0, + mainAxisSpacing: 8.0, + childAspectRatio: 0.7, + ), + itemBuilder: (BuildContext context, int index) { + return Container( + color: index % 2 == 0 ? Colors.red : Colors.black, + ); + }, + ), + GridView.builder( + padding: const EdgeInsets.all(8.0), + itemCount: 20, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 8.0, + mainAxisSpacing: 8.0, + childAspectRatio: 0.7, + ), + itemBuilder: (BuildContext context, int index) { + return Container( + color: index % 2 == 0 ? Colors.red : Colors.black, + ); + }, + ), + ], + ), + ); + } +} + +Widget bottomSheetBuilder(BuildContext ctx) { + return NewPostBottomsheet(); +} diff --git a/lib/src/pages/profile.dart b/lib/src/pages/profile.dart new file mode 100644 index 0000000..f6c1c4e --- /dev/null +++ b/lib/src/pages/profile.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import 'package:veil/src/pages/post.dart'; + +class UserProfilePage extends StatelessWidget { + const UserProfilePage({Key? key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.home), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const PostPage()), + ); + }, + ), + title: const Text('Profile'), + ), + body: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 120, + height: 120, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.red, + ), + ), + const SizedBox(height: 16), + const Text( + 'Name Here', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 24, + ), + ), + const SizedBox(height: 16), + const Divider(), + const SizedBox(height: 16), + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + Chip( + label: const Text('Gender: Female'), + ), + Chip( + label: const Text('Age: 25-34'), + ), + ], + ), + const SizedBox(height: 16), + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey), + borderRadius: BorderRadius.circular(8), + ), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('Karma Points'), + const Text('100'), + ], + ), + ], + ), + ), + const Spacer(), + ElevatedButton( + onPressed: null, + child: const Text('Edit?'), + style: ElevatedButton.styleFrom( + primary: Colors.grey, + minimumSize: const Size(double.infinity, 48), + ), + ), + ], + ), + ); + } +} diff --git a/lib/src/pages/register.dart b/lib/src/pages/register.dart index e69de29..3fab131 100644 --- a/lib/src/pages/register.dart +++ b/lib/src/pages/register.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; + +class RegisterPage extends StatelessWidget { + const RegisterPage({super.key}); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: const [ + Text("Viel App!", style: TextStyle(color: Colors.white, fontSize: 64, fontWeight: FontWeight.w400)), + SizedBox(height: 15), + Text("100% anonymous.\nConnect with like minded people.\nShare your confessions, news or just vent out.", style: TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.w200)), + + ] + ); + } + +} \ No newline at end of file diff --git a/lib/utils/auth/auth.dart b/lib/utils/auth/auth.dart new file mode 100644 index 0000000..f670619 --- /dev/null +++ b/lib/utils/auth/auth.dart @@ -0,0 +1,48 @@ +import 'dart:convert'; + +import 'package:http/http.dart' as http; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; + +/// Checks whether a token is available in the secure storage of device, +/// if no token is found, it throws an exception. +Future findTokenOnDevice() async { + const secureStorage = FlutterSecureStorage(); + final token = await secureStorage.read(key: '${dotenv.env['USER_PROFILE_JWT_KEY']}'); + print('searching token on device'); + print('found = ${token}'); + if (token != null) { + return token; + } else { + throw Exception('Token not found in Secure Storage of this device.'); + } +} + +/// Creates a new guest account, and stores associated JWT securely in device. +Future> createNewGuestAccount(Map? payload) async { + var requiredFields = ['countryId', 'cityId', 'age']; + for (var i = 0; i < requiredFields.length; i++) { + if (payload == null || !payload.containsKey(requiredFields[i])) { + throw Exception('Required fields missing: ${requiredFields[i]}'); + } + } + + final response = await http.post( + Uri.parse('${dotenv.env["BACKEND_URL"]}/auth/v1/guest'), + body: payload, + ); + + print('createNewGuestAccount Response'); + print(response); + + if (response.statusCode == 200) { + // Parse the response body as JSON + final responseBody = json.decode(response.body); + + // Return the parsed JSON as a map + return Map.from(responseBody); + } else { + throw Exception('Failed to create guest account'); + } +} \ No newline at end of file diff --git a/macos/Flutter/Flutter-Debug.xcconfig b/macos/Flutter/Flutter-Debug.xcconfig index c2efd0b..4b81f9b 100644 --- a/macos/Flutter/Flutter-Debug.xcconfig +++ b/macos/Flutter/Flutter-Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/Flutter-Release.xcconfig b/macos/Flutter/Flutter-Release.xcconfig index c2efd0b..5caa9d1 100644 --- a/macos/Flutter/Flutter-Release.xcconfig +++ b/macos/Flutter/Flutter-Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index cccf817..724bb2a 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,8 @@ import FlutterMacOS import Foundation +import shared_preferences_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) } diff --git a/macos/Podfile b/macos/Podfile new file mode 100644 index 0000000..049abe2 --- /dev/null +++ b/macos/Podfile @@ -0,0 +1,40 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/pubspec.lock b/pubspec.lock index b2cb69d..c9713f3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -57,11 +57,35 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_dotenv: + dependency: "direct main" + description: + name: flutter_dotenv + sha256: d9283d92059a22e9834bc0a31336658ffba77089fb6f3cc36751f1fc7c6661a3 + url: "https://pub.dev" + source: hosted + version: "5.0.2" flutter_lints: dependency: "direct dev" description: @@ -70,11 +94,80 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + flutter_secure_storage: + dependency: "direct main" + description: + name: flutter_secure_storage + sha256: "98352186ee7ad3639ccc77ad7924b773ff6883076ab952437d20f18a61f0a7c5" + url: "https://pub.dev" + source: hosted + version: "8.0.0" + flutter_secure_storage_linux: + dependency: transitive + description: + name: flutter_secure_storage_linux + sha256: "0912ae29a572230ad52d8a4697e5518d7f0f429052fd51df7e5a7952c7efe2a3" + url: "https://pub.dev" + source: hosted + version: "1.1.3" + flutter_secure_storage_macos: + dependency: transitive + description: + name: flutter_secure_storage_macos + sha256: "083add01847fc1c80a07a08e1ed6927e9acd9618a35e330239d4422cd2a58c50" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + flutter_secure_storage_platform_interface: + dependency: transitive + description: + name: flutter_secure_storage_platform_interface + sha256: b3773190e385a3c8a382007893d678ae95462b3c2279e987b55d140d3b0cb81b + url: "https://pub.dev" + source: hosted + version: "1.0.1" + flutter_secure_storage_web: + dependency: transitive + description: + name: flutter_secure_storage_web + sha256: "42938e70d4b872e856e678c423cc0e9065d7d294f45bc41fc1981a4eb4beaffe" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter_secure_storage_windows: + dependency: transitive + description: + name: flutter_secure_storage_windows + sha256: fc2910ec9b28d60598216c29ea763b3a96c401f0ce1d13cdf69ccb0e5c93c3ee + url: "https://pub.dev" + source: hosted + version: "2.0.0" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + http: + dependency: "direct main" + description: + name: http + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.dev" + source: hosted + version: "0.13.6" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" js: dependency: transitive description: @@ -123,6 +216,110 @@ packages: url: "https://pub.dev" source: hosted version: "1.8.2" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: "2ae08f2216225427e64ad224a24354221c2c7907e448e6e0e8b57b1eb9f10ad1" + url: "https://pub.dev" + source: hosted + version: "2.1.10" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" + url: "https://pub.dev" + source: hosted + version: "2.0.6" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: f53720498d5a543f9607db4b0e997c4b5438884de25b0f73098cc2671a51b130 + url: "https://pub.dev" + source: hosted + version: "2.1.5" + platform: + dependency: transitive + description: + name: platform + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + process: + dependency: transitive + description: + name: process + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" + source: hosted + version: "4.2.4" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "858aaa72d8f61637d64e776aca82e1c67e6d9ee07979123c5d17115031c1b13b" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "7fa90471a6875d26ad78c7e4a675874b2043874586891128dc5899662c97db46" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "0c1c16c56c9708aa9c361541a6f0e5cc6fc12a3232d866a687a7b7db30032b07" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "9d387433ca65717bbf1be88f4d5bb18f10508917a8fa2fb02e0fd0d7479a9afa" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: fb5cf25c0235df2d0640ac1b1174f6466bd311f621574997ac59018a6664548d + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: "74083203a8eae241e0de4a0d597dbedab3b8fef5563f33cf3c12d7e93c655ca5" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "5e588e2efef56916a3b229c3bfe81e6a525665a454519ca51dbcc4236a274173" + url: "https://pub.dev" + source: hosted + version: "2.2.0" sky_engine: dependency: transitive description: flutter @@ -176,6 +373,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.16" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + url: "https://pub.dev" + source: hosted + version: "1.3.1" vector_math: dependency: transitive description: @@ -184,5 +389,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + win32: + dependency: transitive + description: + name: win32 + sha256: a6f0236dbda0f63aa9a25ad1ff9a9d8a4eaaa5012da0dc59d21afdb1dc361ca4 + url: "https://pub.dev" + source: hosted + version: "3.1.4" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 + url: "https://pub.dev" + source: hosted + version: "1.0.0" sdks: dart: ">=2.19.6 <3.0.0" + flutter: ">=3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index bd32adc..9142695 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,11 +30,15 @@ environment: dependencies: flutter: sdk: flutter + shared_preferences: 2.1.0 + flutter_dotenv: ^5.0.2 + flutter_secure_storage: ^8.0.0 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 + http: ^0.13.6 dev_dependencies: flutter_test: