Building a social media app with AWS Amplify and Flutter(PART 2)

I love creating and writing about the creation of software.
Search for a command to run...

I love creating and writing about the creation of software.
Yes!!
This series outlines the steps involved in build an MVP for a social Medial Application using the Amplify Framework and flutter
In PART 1 and PART 2 of this series, we covered how to configure Amplify with Flutter, create login/registration screens and update profile screen. In this post, we'll look at how to let a user add and display all posts in the database in real time....
Watch the complete Video on Youtube https://www.youtube.com/watch?v=kKX-8L_R2XM Prerequisites Before proceeding make sure you have these dependencies Docker Python 3.11 and above AWS CLI Full access to a foundation model. For this workshop, we'll...

Introduction In a previous workshop, Building event-driven applications with AWS sam and python we built an e-commerce ordering service using AWS SAM, API Gateway, Lambda and Python. Here's the solutions architecture. In that workshop, whenever a ne...

Github Repository https://github.com/EducloudHQ/introduction_to_gen_ai Skill up with serverless on Educloud https://www.educloud.academy/content/da99ad07-7efa-41e7-ba50-b18e6b89e10d This post is an introductory lesson to building AI-enhanced serverle...

Introduction Serverless computing is a cloud-based approach to application development that eliminates the need for provisioning and managing servers. Instead, developers focus on writing code that is triggered by events such as HTTP requests or data...

https://github.com/trey-rosius/sam_stepfunctions Hey!!! How you doing? In this post, we’ll look at how to build a workflow, using SAM as IaC, Appsync, and python. Prerequisites Install AWS Cli (https://docs.aws.amazon.com/cli/latest/userguide/cli-c...

1 October, 2021 - Loom Recording - Watch Video
PART 1
Hi there,
in the first part of this series, we briefly introduced and added amplify to our Flutter application.
In this second part, we'll continue from where we left off.
FULL SOURCE CODE FOR THIS SECTION IS IN THIS BRANCH
amplify related requests. Future<void> _initializeApp() async{
await _configureAmplify();
}
final AmplifyDataStore _amplifyDataStore = AmplifyDataStore(modelProvider: ModelProvider.instance,);
Future<void> _configureAmplify() async {
try{
await Amplify.addPlugins([
_amplifyDataStore,
AmplifyAuthCognito(),
AmplifyAPI(),
AmplifyStorageS3()
]);
// Once Plugins are added, configure Amplify
await Amplify.configure(amplifyconfig);
} catch(e) {
print('an error occured during amplify configuration: $e');
}
}
From the code above, we add the Datastore, Auth,Api and storage plugins, then run Amplify.configure().
Now, call the _initializeApp() function in the initState method of yourmain.dart file.
@override
void initState() {
_initializeApp();
super.initState();
}
Here's the full code for the main.dart file main.dart.
In the main.dart file, the homepage is wrapped with a MultiProvider method, gotten from the provider state management plugin we added earlier to the pubspec.yaml file.
We provide the ProfileRepository and SharedPrefUtils.
home: MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => ProfileRepository.instance(),),
ChangeNotifierProvider(create: (_) => SharedPrefsUtils.instance(),),
],
child: HomePage(),
)
SharedPrefUtils contains methods to save, get and delete shared preferences from our app. We use it to save and retrieve the userId whenever we need it.
ProfileRepository has methods, getters, and setters for all dependencies we'll need in the profile section of our application.
In the homepage.dart the application retrieves the userId value stored in shared preferences and checks if it has a value or if it's null.
If null, then the user doesn't exist, meaning no user has logged into the app from that device yet. So you get directed to the login screen.
While setting up the authentication category for Amplify, we choose to have regular username and password signup, alongside google sign up.
And if you followed the link I attached, you must have set up google credentials properly.
Let's take a look at the code for logging in to our app using google.
This code is in the loginRepository.dart file .
Future<void>googleSignIn(BuildContext context) async{
googleLoading = true;
try {
var res = await Amplify.Auth.signInWithWebUI(provider: AuthProvider.google);
isSignedIn = res.isSignedIn;
if(isSignedIn){
googleLoading = false;
retrieveCurrentUser().then((AuthUser authUser) async{
SharedPrefsUtils.instance().saveUserId(authUser.userId).then((value) {
print("user id saved successfully");
});
print("User id is"+authUser.userId);
List<User> user = await Amplify.DataStore.query(User.classType, where: User.ID.eq(authUser.userId));
if(user.isNotEmpty){
Navigator.push(context, MaterialPageRoute(builder: (context){
// return RegisterScreen();
//return LoginScreen();
return ChangeNotifierProvider(create: (_)=>ProfileRepository.instance(),
child: EditProfileScreen(authUser.userId),);
}));
}else{
Navigator.push(context, MaterialPageRoute(builder: (context){
// return RegisterScreen();
//return LoginScreen();
return ChangeNotifierProvider(create: (_)=>ProfileRepository.instance(),
child: CreateProfileScreen(),);
}));
}
});
}else{
googleLoading = false;
}
} on AmplifyException catch (e) {
print(e.message);
googleLoading = false;
}
}
Future<AuthUser>retrieveCurrentUser() async{
AuthUser authUser = await Amplify.Auth.getCurrentUser();
return authUser;
}
What this code does is, firstly, it sets a loading indicator value to true. On the loginscreen we'll display or not display a loading indicator when the google sign-in button is clicked, based on this value.
Then we sign in the user with Amplify.Auth.signInWithWebUI.
If successful, we call a method retrieveCurrentUser which retrieves user information like userId, email. We save userId to shared preferences.
Next, we check if a user with the same userId already exists in our datastore. If they do, then they are a returning user. So we navigate to the updateProfileScreen.dart screen.
Else, they are new, so we navigate to createProfileScreen.dart screen.
Please refer to the github repository for the full source code.
Firstly, we upload the user's profile picture and get its public URL.
We first assign some metadata such as the name and description of the picture to S3UploadFileOptions and also set the accessLevel of the image to StorageAccessLevel.guest.
StorageAccessLevel is an enumeration with values such as guest, private, protected.
Using Amplify.Storage.uploadFile, firstly we pass the key, which is a unique identifier, then the local which is the relative path to the local file, and the options object we created above.S3UploadFileOptions.
We then use await Amplify.Storage.getUrl(key: profilePicKey) to retrieve the URL.
Map<String, String> metadata = <String, String>{};
metadata['name'] = "user_$uuid";
metadata['desc'] = 'A profile picture ';
S3UploadFileOptions options = S3UploadFileOptions(accessLevel: StorageAccessLevel.guest, metadata: metadata);
try {
UploadFileResult result = await Amplify.Storage.uploadFile(
key: uuid,
local: croppedFile,
options: options
);
profilePicKey = result.key;
print("the key is "+profilePicKey);
GetUrlResult resultDownload = await Amplify.Storage.getUrl(key: profilePicKey);
print(resultDownload.url);
profilePic = resultDownload.url;
loading = false;
} on StorageException catch (e) {
print("error message is" + e.message);
loading= false;
}
saveUserProfileDetails
Future<void>saveUserProfileDetails() async{
loading = true;
User newUser = User(
id:userId,username:username,firstName: firstNamesController.text.trim(),lastName: lastNamesController.text.trim(),
profilePicUrl: profilePic,email: email,createdOn: TemporalDateTime.now(),isVerified: true);
await Amplify.DataStore.save(newUser).then((_) => loading = false);
}
The above function saves userId, username,firstName etc to the datastore.
updateProfileDetails
Future<void>updateUserProfileDetails(String userId) async{
loading = true;
List<User> user = await Amplify.DataStore.query(User.classType, where: User.ID.eq(userId));
User newUser = user[0].copyWith(id: user[0].id,firstName: firstNamesController.text.trim(),lastName: lastNamesController.text.trim(),
profilePicUrl: profilePic,updatedOn: TemporalDateTime.now());
await Amplify.DataStore.save(newUser).then((_) => loading = false);
}
getUserProfile
Future<User>getUserProfile(String userId) async{
List<User> user = await Amplify.DataStore.query(User.classType, where: User.ID.eq(userId));
print(user[0]);
firstNamesController.text = user[0].firstName;
lastNamesController.text = user[0].lastName!;
profilePic =user[0].profilePicUrl!;
return user[0];
}
}
After user details have been saved properly, we navigate to the HomePage.
FULL SOURCE CODE FOR THIS SECTION IS IN THIS BRANCH