Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,20 @@ jobs:
- name: Build Android apk For Production
run: melos run build-apk

# Install Firebase CLI
- name: Install Firebase CLI
run: curl -sL https://firebase.tools | bash

# Distribute APK to Firebase App Distribution
- name: Distribute APK
run: |
firebase appdistribution:distribute apps/app_core/build/app/outputs/flutter-apk/app-prod-release.apk \
--app "${{ secrets.FIREBASE_APP_ID }}" \
--groups "7Span-Internal" \
--release-notes "${{ github.event.head_commit.message }}"
env:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}

- name: Upload the build Artifact
uses: actions/upload-artifact@v4
with:
Expand Down
24 changes: 12 additions & 12 deletions apps/app_core/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.flutter.boilerplate.app\n";
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.demo.app;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
Expand All @@ -535,7 +535,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.app;
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.demo.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
Expand Down Expand Up @@ -650,7 +650,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.flutter.boilerplate.app\n";
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.demo.app;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
Expand Down Expand Up @@ -701,7 +701,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.flutter.boilerplate.app\n";
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.demo.app;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
Expand All @@ -728,7 +728,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.app;
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.demo.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
Expand Down Expand Up @@ -759,7 +759,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.app;
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.demo.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
Expand Down Expand Up @@ -847,7 +847,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.app;
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.demo.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
Expand Down Expand Up @@ -951,7 +951,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.app;
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.demo.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
Expand Down Expand Up @@ -1050,7 +1050,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.app;
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.demo.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
Expand Down Expand Up @@ -1154,7 +1154,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.app;
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.demo.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
Expand Down Expand Up @@ -1258,7 +1258,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.app;
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.demo.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
Expand Down Expand Up @@ -1357,7 +1357,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.app;
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.boilerplate.demo.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions apps/app_core/ios/Runner/info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@
<string>971758003871-288i8740a8i9re9hiki2p84uvbd8busq.apps.googleusercontent.com</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSUserNotificationUsageDescription</key>
<string>We need notification permissions to keep you updated.</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>NSUserNotificationUsageDescription</key>
<string>We need notification permissions to keep you updated.</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
Expand All @@ -57,4 +57,4 @@
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
</plist>
2 changes: 2 additions & 0 deletions apps/app_core/lib/app/config/api_endpoints.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
class ApiEndpoints {

static const pageSize = 5;
static const login = '/api/v1/login';
static const signup = '/api/register';
static const profile = '/api/users';
Expand Down
77 changes: 40 additions & 37 deletions apps/app_core/lib/modules/home/bloc/home_bloc.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:api_client/api_client.dart';
import 'package:app_core/app/config/api_endpoints.dart';
import 'package:app_core/modules/home/model/post_response_model.dart';
import 'package:app_core/modules/home/repository/home_repository.dart';
import 'package:bloc_concurrency/bloc_concurrency.dart';
Expand All @@ -12,41 +13,43 @@ part 'home_state.dart';
class HomeBloc extends Bloc<HomeEvent, HomeState> {
HomeBloc({required this.repository}) : super(const HomeState()) {
on<FetchPostsEvent>(_fetchPosts);
on<LoadMorePostsEvent>(_onLoadMorePosts, transformer: droppable());
on<LoadMorePostsEvent>(
_onLoadMorePosts,
transformer: droppable(),
);
}

final HomeRepository repository;

int _page = 1;
final int _limit = 5;

Future<void> _fetchPosts(
FetchPostsEvent event,
Emitter<HomeState> emit,
) async {
_page = 1;

emit(const HomeState(apiStatus: ApiStatus.loading));

final response =
await repository.fetchPostData(page: _page, limit: _limit).run();
final response = await repository.fetchPostData().run();

response.fold((error) => emit(state.copyWith(apiStatus: ApiStatus.error)), (
response,
) {
if (response.isEmpty) {
emit(const HomeState(apiStatus: ApiStatus.empty, hasReachedMax: true));
} else {
emit(
state.copyWith(
postList: response,
apiStatus: ApiStatus.loaded,
hasReachedMax: response.length < _limit,
),
);
_page++;
}
});
response.fold(
(error) => emit(state.copyWith(apiStatus: ApiStatus.error)),
(response) {
if (response.isEmpty) {
emit(
const HomeState(
apiStatus: ApiStatus.empty,
hasReachedMax: true,
),
);
} else {
emit(
state.copyWith(
postList: response,
apiStatus: ApiStatus.loaded,
hasReachedMax: response.length < ApiEndpoints.pageSize,
),
);
}
},
);
}

Future<void> _onLoadMorePosts(
Expand All @@ -56,19 +59,19 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
if (state.hasReachedMax) return;

final response =
await repository.fetchPostData(page: _page, limit: _limit).run();
await repository.fetchPostData(page: state.nextPage).run();

response.fold((error) => emit(state.copyWith(apiStatus: ApiStatus.error)), (
response,
) {
emit(
state.copyWith(
postList: List.of(state.postList)..addAll(response),
apiStatus: ApiStatus.loaded,
hasReachedMax: response.length < _limit,
),
);
_page++;
});
response.fold(
(error) => emit(state.copyWith(apiStatus: ApiStatus.error)),
(response) {
emit(
state.copyWith(
postList: List.of(state.postList)..addAll(response),
apiStatus: ApiStatus.loaded,
hasReachedMax: response.length < ApiEndpoints.pageSize,
),
);
},
);
}
}
17 changes: 16 additions & 1 deletion apps/app_core/lib/modules/home/bloc/home_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,24 @@ class HomeState extends Equatable {
});

final ApiStatus apiStatus;
final List<PostResponseModel> postList; // The currently loaded users
final List<PostResponseModel>
postList; // The currently loaded users
final bool hasReachedMax; // Whether all pages are loaded

/// if API pagination starts with 1:
/// ```dart
/// int get nextPage =>
/// (list.length / pageSize).floor() + 1;
///```
///
/// if API pagination starts with 0:
/// ```dart
/// int get nextPage =>
/// (list.length / pageSize).ceil();
/// ```
int get nextPage =>
(postList.length / ApiEndpoints.pageSize).floor() + 1;

/// Copy the state with new values.

@override
Expand Down
27 changes: 17 additions & 10 deletions apps/app_core/lib/modules/home/repository/home_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import 'package:fpdart/fpdart.dart';

abstract interface class IHomeRepository {
TaskEither<Failure, List<PostResponseModel>> fetchPostData({
required int page,
required int limit,
int page = 1,
});

TaskEither<Failure, bool> setPlayerId(String playerId);
Expand All @@ -20,40 +19,48 @@ abstract interface class IHomeRepository {
class HomeRepository implements IHomeRepository {
@override
TaskEither<Failure, List<PostResponseModel>> fetchPostData({
required int page,
required int limit,
int page = 1,
}) {
return makefetchPostsRequest(page, limit)
return makeFetchPostsRequest(page)
.chainEither(RepositoryUtils.checkStatusCode)
.chainEither(
(response) => RepositoryUtils.mapToModel(() {
// ignore: prefer_final_locals
var postList = <PostResponseModel>[];
for (final postModel in response.data as List<dynamic>) {
postList.add(
PostResponseModel.fromJson(postModel as Map<String, dynamic>),
PostResponseModel.fromJson(
postModel as Map<String, dynamic>,
),
);
}
return postList;
}),
);
}

TaskEither<Failure, Response> makefetchPostsRequest(int page, int limit) {
TaskEither<Failure, Response> makeFetchPostsRequest(int page) {
return baseApiClient.request(
path: ApiEndpoints.posts,
queryParameters: {'_page': page, '_limit': limit},
queryParameters: {
'_page': page,
'_limit': ApiEndpoints.pageSize,
},
);
}

@override
TaskEither<Failure, bool> setPlayerId(String playerID) =>
getIt<IHiveService>()
.setPlayerId(playerID)
.flatMap((r) => _sendPlayerIdToServer(playerID).map((r) => true));
.flatMap(
(r) => _sendPlayerIdToServer(playerID).map((r) => true),
);

/// Make API call to send the player ID to the server
TaskEither<Failure, Response> _sendPlayerIdToServer(String playerID) {
TaskEither<Failure, Response> _sendPlayerIdToServer(
String playerID,
) {
return userApiClient.request(
path: 'Endpoint',
queryParameters: {'playerId': playerID},
Expand Down
Loading