Skip to content

Commit

Permalink
still cooking 👾👾
Browse files Browse the repository at this point in the history
  • Loading branch information
olawills committed Oct 24, 2023
1 parent 8f1f9ee commit a6dca49
Show file tree
Hide file tree
Showing 33 changed files with 409 additions and 304 deletions.
52 changes: 39 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,56 @@
# Sparkz Dating App
### Under Development
### Project Directory

- Project Directory
```shell
app
bloc
services
UI
generated
l10n
localization
src
```

### Screenshots
![Image 1](assets/images/1.png) ![Image 2](assets/images/2.png)
![image 3](assets/images/3.png) ![image 4](assets/images/4.png)



<p> The Services folder contains all business logic and functions that interacts with the Backend </p>
<p> The Ui folder contains all the necessary files for developing and maintaining the UI</p>
<h5> The src folder contains all the necessary files for developing and maintaining the UI</h5>

<h5>Inside the UI they are, two folders, shared and the views</h5>
<p>The shared folder contains UI tools, widgets, extensions and helpful strings</p>
<p>The view folder contains all the app views such as Login View, Sign up View, Forgot Password View etc.</p>
<h5>The shared folder contains UI tools, widgets, extensions and helpful strings</h5>
<h5>The view folder contains all the app views such as Login View, Sign up View, Forgot Password View etc.</h5>

<h5>The view folder are are seperated in two ways, which are, the Features folder, containing the app views after authentication e.g Home View, Chat View etc</h5>
<h5>The other views are the views for the various means of authentication and each routing is handled by the GoRouter package, from the code a simple navigation as been customized to _navigationService.pushScreen(context, LoginScreen.route)</h5>

##### Build App
You can build the app using the commands below

for Android

```
## development: flutter build apk -t lib/main.dart --flavor dev
## production: flutter build apk -t lib/main.dart --flavor prod
```

for IOS

```
Coming Soon
```



### Olawills Dating App with Flutter, Node JS, Express Js and Bloc for State management
#### Olawills Dating App with Flutter, Node JS, Express Js and Bloc for State management

<p>This project is going to be a large and comprehensive with lots of features, bug fixings, and possible more addition of developers <p>
<p>This project will be using it's own backend service which i will be creating myself with tge help of node and express js</p>
<p> The project uses the MVVM pattern and Dependency injection (GetIt) to structure and organize all files and folders
<p>By the end of this project i will be providing the screenshot and also a detailed view of each folders and codes</p>
<h5>This project is going to be a large and comprehensive with lots of features, bug fixings, and possible more addition of developers </h5>
<h5>This project will be using it's own backend service which i will be creating myself with tge help of node and express js</h5>
<h5> The project uses the MVVM pattern and Dependency injection (GetIt) to structure and organize all files and folders
<h5>By the end of this project i will be providing the screenshot and also a detailed view of each folders and codes</h5>

<h5>To enjoy Flutter utils stay follow me on my Linkedln and Twitter page which are <a href ="https://www.linkedln.com/in/olawills">Linkedln page</a> and <a href ="https://www.twitter.com/olawillfFlutter"> Twitter Page</a></h5>

A new Flutter project.
Binary file added assets/images/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion lib/app/common/constants/app_constant.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ double height = 852.h;
double width = 393.w;

const Duration veryLongDuration = Duration(seconds: 3);
const Duration nearbyUsers = Duration(seconds: 5);
const Duration nearbyUsers = Duration(minutes: 3);

const profileUrl =
"https://media.istockphoto.com/id/1451587807/vector/user-profile-icon-vector-avatar-or-person-icon-profile-picture-portrait-symbol-vector.jpg?s=612x612&w=0&k=20&c=yDJ4ITX1cHMh25Lt1vI1zBn2cAKKAlByHBvPJ8gEiIg=";
Expand Down
6 changes: 3 additions & 3 deletions lib/app/common/utils/toast_messages.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class ToastMessages {

ToastMessages._internal();

showToastServerError(NetworkExceptions error) {
static showToastServerError(NetworkExceptions error) {
Fluttertoast.showToast(
msg: NetworkExceptions.getErrorMessage(error),
fontSize: 16,
Expand All @@ -19,15 +19,15 @@ class ToastMessages {
gravity: ToastGravity.BOTTOM);
}

showToastSuccessMessage(String message) {
static showToastSuccessMessage(String message) {
return Fluttertoast.showToast(
msg: message,
gravity: ToastGravity.BOTTOM,
backgroundColor: Color(AppColors.darkRed.value),
);
}

showToastErrorMessage(String message) {
static showToastErrorMessage(String message) {
return Fluttertoast.showToast(
msg: message,
gravity: ToastGravity.BOTTOM,
Expand Down
2 changes: 1 addition & 1 deletion lib/app/common/widgets/display_pic_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class UserDisplayPicture extends StatelessWidget {
backgroundColor: AppColors.darkRed,
child: CircleAvatar(
radius: isLargeDp ? 76.r : 18.r,
backgroundImage: AssetImage(imageUrl),
backgroundImage: NetworkImage(imageUrl),
),
),
);
Expand Down
70 changes: 33 additions & 37 deletions lib/app/core/config/injection_container.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,41 +20,37 @@ import '../network/dio_helper.dart';

GetIt serviceLocator = GetIt.instance;

class ServiceLocator {
ServiceLocator._();

static void init() {
// Blocs
serviceLocator.registerFactory<AuthBloc>(() => AuthBloc());
serviceLocator.registerFactory<OnboardingBloc>(() => OnboardingBloc());
serviceLocator.registerFactory<FetchUserBloc>(() => FetchUserBloc());
serviceLocator.registerFactory<InterestBloc>(() => InterestBloc());
serviceLocator.registerFactory<GpsBloc>(() => GpsBloc());
serviceLocator.registerFactory<LocationBloc>(() => LocationBloc());

// Cubit
serviceLocator
.registerFactory<BottomNavigationCubit>(() => BottomNavigationCubit());
serviceLocator.registerFactory<InternetConnectionCubit>(
() => InternetConnectionCubit(connectivity: serviceLocator()));

// Data Source
serviceLocator.registerFactory<AuthRemoteDataSource>(
() => AuthRemoteDataSourceImpl());
serviceLocator.registerFactory<UserRemoteDataSource>(
() => UserRemoteDataSourceImpl());
serviceLocator.registerFactory<AuthInfoRemoteDataSource>(
() => AuthInfoRemoteDataSourceImpl());

// Repositories
serviceLocator.registerFactory<AuthRepository>(() => AuthRepository());
serviceLocator
.registerFactory<AuthInfoRepository>(() => AuthInfoRepository());
serviceLocator.registerFactory<UserRepository>(() => UserRepository());

// Dio
serviceLocator.registerLazySingleton<DioHelper>(() => DioHelper());
serviceLocator.registerLazySingleton<Dio>(() => Dio());
serviceLocator.registerLazySingleton<Connectivity>(() => Connectivity());
}
Future<void> setUpServiceLocator() async {
// Blocs
serviceLocator.registerFactory<AuthBloc>(() => AuthBloc());
serviceLocator.registerFactory<OnboardingBloc>(() => OnboardingBloc());
serviceLocator.registerFactory<FetchUserBloc>(() => FetchUserBloc());
serviceLocator.registerFactory<InterestBloc>(() => InterestBloc());
serviceLocator.registerFactory<GpsBloc>(() => GpsBloc());
serviceLocator.registerFactory<LocationBloc>(() => LocationBloc());

// Cubit
serviceLocator
.registerFactory<BottomNavigationCubit>(() => BottomNavigationCubit());
serviceLocator.registerFactory<InternetConnectionCubit>(
() => InternetConnectionCubit(connectivity: serviceLocator()));

// Data Source
serviceLocator
.registerFactory<AuthRemoteDataSource>(() => AuthRemoteDataSourceImpl());
serviceLocator
.registerFactory<UserRemoteDataSource>(() => UserRemoteDataSourceImpl());
serviceLocator.registerFactory<AuthInfoRemoteDataSource>(
() => AuthInfoRemoteDataSourceImpl());

// Repositories
serviceLocator.registerFactory<AuthRepository>(() => AuthRepository());
serviceLocator
.registerFactory<AuthInfoRepository>(() => AuthInfoRepository());
serviceLocator.registerFactory<UserRepository>(() => UserRepository());

// Dio
serviceLocator.registerLazySingleton<DioHelper>(() => DioHelper());
serviceLocator.registerLazySingleton<Dio>(() => Dio());
serviceLocator.registerLazySingleton<Connectivity>(() => Connectivity());
}
28 changes: 28 additions & 0 deletions lib/app/core/domain/flavours/app_flavour.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import 'dart:async';
import 'dart:developer';

import 'package:dating_app/app/core/domain/all_blocs.dart';

import '../../../../localization/localization.dart';
import '../../core.dart';
import '../../logger/app_logger.dart';

Future<void> bootstrap(FutureOr<Widget> Function() builder) async {
FlutterError.onError = (details) {
log(details.exceptionAsString(), stackTrace: details.stack);
};

await runZonedGuarded(
() async {
runApp(
initializeLocation(
child: MultiBlocProvider(
providers: AppBlocProviders.allBlocProviders,
child: await builder(),
),
),
);
},
(error, stackTrace) => Log.debug(error.toString(), [stackTrace]),
);
}
6 changes: 6 additions & 0 deletions lib/app/core/domain/flavours/dev_app.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import 'package:dating_app/app/core/domain/flavours/app_flavour.dart';
import 'package:dating_app/app/core/domain/sparkz_config.dart';

void main() {
bootstrap(() => const SparkzConfig());
}
6 changes: 6 additions & 0 deletions lib/app/core/domain/flavours/prod_app.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import 'package:dating_app/app/core/domain/flavours/app_flavour.dart';
import 'package:dating_app/app/core/domain/sparkz_config.dart';

void main() {
bootstrap(() => const SparkzConfig());
}
26 changes: 24 additions & 2 deletions lib/app/core/network/dio_helper.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:dating_app/app/core/network/dio_interceptors.dart';
import 'package:dating_app/app/core/network/request_retrier.dart';
import 'package:dio/dio.dart';

import '../services/api_url.dart';
Expand All @@ -16,7 +18,14 @@ class DioHelper {
sendTimeout: const Duration(milliseconds: 20000),
),
);
dio.interceptors.add(DioInterceptor());
dio.interceptors.add(
RetryOnConnectionChangeInterceptor(
requestRetrier: DioConnectivityRequestRetrier(
dio: Dio(),
connectivity: Connectivity(),
),
),
);
}

static Future<Response> postData({
Expand All @@ -38,10 +47,23 @@ class DioHelper {
Map<String, dynamic>? query,
String? token,
}) async {
dio.options.headers = ApiConfig.header;
return await dio.get(
path,
queryParameters: query,
);
}

static Future<Response> updateData({
required String path,
Map<String, dynamic>? query,
required String data,
String? token,
}) async {
dio.options.headers = ApiConfig.header;
return await dio.put(
path,
data: data,
queryParameters: query,
);
}
}
43 changes: 27 additions & 16 deletions lib/app/core/network/dio_interceptors.dart
Original file line number Diff line number Diff line change
@@ -1,31 +1,42 @@
import 'package:dating_app/app/core/logger/app_logger.dart';
import 'dart:io';

import 'package:dating_app/app/core/network/request_retrier.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';

class RetryOnConnectionChangeInterceptor extends Interceptor {
final DioConnectivityRequestRetrier requestRetrier;
RetryOnConnectionChangeInterceptor({required this.requestRetrier});

class DioInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
Log.info('==================START====================');
Log.info(
debugPrint(
'Request => ${options.baseUrl} ${options.path}${options.queryParameters}');
Log.info('Request: ${options.method} ${options.uri}');
Log.info('Data: ${options.data}');
return super.onRequest(options, handler);
debugPrint('Data: ${options.data}');
return handler.next(options);
}

@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
Log.debug(
'Response => StatusCode: ${response.statusCode} ${response.statusMessage}');
Log.verbose('Response => Body ${response.data}');
Log.verbose('Headers => ${response.headers}');
return super.onResponse(response, handler);
debugPrint('Response => ${response.data}');
return handler.next(response);
}

@override
void onError(DioException err, ErrorInterceptorHandler handler) {
final options = err.requestOptions;
Log.error(options.method); //Debug log
Log.error('${err.message}', 'Error: ${err.error}');
return super.onError(err, handler);
if (_shouldRetry(err)) {
try {
requestRetrier.scheduleRequestRetry(err.requestOptions);
} catch (e) {
e;
}
}
err;
}

bool _shouldRetry(DioException err) {
return err.type == DioExceptionType.unknown &&
err.error != null &&
err.error is SocketException;
}
}
32 changes: 32 additions & 0 deletions lib/app/core/network/request_retrier.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import 'dart:async';

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:dio/dio.dart';


class DioConnectivityRequestRetrier {
final Dio dio;
final Connectivity connectivity;
DioConnectivityRequestRetrier({
required this.dio,
required this.connectivity,
});
Future<Response> scheduleRequestRetry(RequestOptions requestOptions) async {
StreamSubscription? streamSubscription;
final responseCompleter = Completer<Response>();

streamSubscription = connectivity
.onConnectivityChanged
.listen((event) async {
if (event != ConnectivityResult.none) {
streamSubscription?.cancel();

// Complete the completer instead of returning
responseCompleter.complete(
dio.fetch(requestOptions),
);
}
});
return responseCompleter.future;
}
}
6 changes: 2 additions & 4 deletions lib/app/core/routes/app_router.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import 'package:dating_app/app/core/core.dart';

import '../logger/app_logger.dart';

class AppRouter {
static final RouterConfig<Object> routerConfig = RouterConfig(
routerDelegate: router.routerDelegate,
Expand Down Expand Up @@ -159,8 +157,8 @@ final GoRouter _router = GoRouter(
),
],
redirect: (BuildContext context, GoRouterState state) async {
Log.debug(state.matchedLocation);
Log.debug(await LocalDataStorage.instance.getFirstTime());
debugPrint(state.matchedLocation);
debugPrint('${await LocalDataStorage.instance.getFirstTime()}');
if (state.matchedLocation == LoginScreen.path) {
if (await LocalDataStorage.instance.getFirstTime()) {
return OnBoardingScreen.path;
Expand Down
Loading

0 comments on commit a6dca49

Please sign in to comment.