Skip to content

Commit

Permalink
Отображение количества реакций (#332)
Browse files Browse the repository at this point in the history
Co-authored-by: Daria Sokolova <dasa.vzn@mail.ru>
Co-authored-by: Yurin Andrey <100288192+Namxobick@users.noreply.github.com>
  • Loading branch information
3 people authored May 11, 2024
1 parent 4c64b45 commit 0e79003
Show file tree
Hide file tree
Showing 21 changed files with 468 additions and 120 deletions.
Binary file added assets/images/reactions/active_like.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/reactions/angry.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/reactions/confused.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/reactions/default_like.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/reactions/facepalm.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/reactions/laugh.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/reactions/like.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/reactions/love.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/reactions/sad.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,28 @@ import 'package:unn_mobile/core/models/user_data.dart';
import 'package:unn_mobile/core/services/interfaces/getting_profile_of_current_user_service.dart';
import 'package:unn_mobile/core/services/interfaces/user_data_provider.dart';

class TypeOfCurrentUser {
class CurrentUserSyncStorage {
final UserDataProvider _userDataProvider =
Injector.appInstance.get<UserDataProvider>();
final GettingProfileOfCurrentUser _gettingProfileOfCurrentUser =
Injector.appInstance.get<GettingProfileOfCurrentUser>();

/// Хранит тип текущего пользователя: [Type] ([StudentData] или [EmployeeData]) или [Null] в случае ошибки
Type typeOfUser = StudentData;
UserData? _currentUserData;

/// Получает тип авторизованного пользователя. Возвращает типы ([Type]) [StudentData] или [EmployeeData], или [Null] при ошибке
Future<Type> getTypeOfCurrentUser() async {
final UserData? type = await _userDataProvider.getData() ??
await _gettingProfileOfCurrentUser.getProfileOfCurrentUser();
return type.runtimeType;
}
/// Хранит информацию о текущем пользователе
UserData? get currentUserData => _currentUserData;

/// Хранит тип текущего пользователя: [Type] ([StudentData] или [EmployeeData]) или [Null] в случае ошибки
Type get typeOfUser => _currentUserData.runtimeType;

/// Обновляет тип текущего пользователя
Future<void> updateTypeOfCurrentUser() async {
typeOfUser = await getTypeOfCurrentUser();
/// Обновляет хранимую информацию о текущем пользователе
Future<void> updateCurrentUserInfo() async {
if (await _userDataProvider.isContained()) {
_currentUserData = await _userDataProvider.getData();
} else {
_currentUserData =
await _gettingProfileOfCurrentUser.getProfileOfCurrentUser();
_userDataProvider.saveData(_currentUserData);
}
}
}
52 changes: 45 additions & 7 deletions lib/core/models/rating_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,39 @@ class _KeysForUserInfoJsonConverter {
static const String photoSrc = 'PHOTO_SRC';
}

const String _reactionAssetsDirectory = 'assets/images/reactions';
const Map<ReactionType, String> _reactionAssets = {
ReactionType.like: '$_reactionAssetsDirectory/like.png',
ReactionType.angry: '$_reactionAssetsDirectory/angry.png',
ReactionType.cry: '$_reactionAssetsDirectory/sad.png',
ReactionType.laugh: '$_reactionAssetsDirectory/laugh.png',
ReactionType.facepalm: '$_reactionAssetsDirectory/facepalm.png',
ReactionType.kiss: '$_reactionAssetsDirectory/love.png',
ReactionType.wonder: '$_reactionAssetsDirectory/confused.png',
};

const Map<ReactionType, String> _reactionNames = {
ReactionType.like: 'Нравится',
ReactionType.angry: 'Ъуъ!',
ReactionType.cry: 'Печаль',
ReactionType.laugh: 'Смешно',
ReactionType.facepalm: 'Facepalm',
ReactionType.kiss: 'Восторг',
ReactionType.wonder: 'Ого!',
};

enum ReactionType {
like,
kiss,
laugh,
wonder,
cry,
angry,
facepalm,
angry,
; // О_о

String get assetName => _reactionAssets[this]!;
String get caption => _reactionNames[this]!;
}

class ReactionUserInfo {
Expand Down Expand Up @@ -65,6 +90,14 @@ class RatingList {
}
}

int getTotalNumberOfReactions() {
int total = 0;
for (final element in _ratingList.values) {
total += element.length;
}
return total;
}

void removeReaction(
int userId,
) {
Expand All @@ -78,12 +111,7 @@ class RatingList {
if (reactionType != null) {
return _ratingList[reactionType]?.length;
}

int totalSize = 0;
for (final list in _ratingList.values) {
totalSize += list.length;
}
return totalSize;
return getTotalNumberOfReactions();
}

List<ReactionUserInfo>? getUsers([ReactionType? reactionType]) {
Expand All @@ -107,6 +135,16 @@ class RatingList {
return entry.value.isNotEmpty ? entry.key : null;
}

ReactionUserInfo? getReactionInfoByUser(int bitrixId) {
final entry = _ratingList.entries.firstWhere(
(entry) => entry.value.any((user) => user._bitrixId == bitrixId),
orElse: () => const MapEntry(ReactionType.like, []),
);
return entry.value.isNotEmpty
? entry.value.firstWhere((element) => element._bitrixId == bitrixId)
: null;
}

factory RatingList.fromJson(Map<String, Object?> jsonMap) {
final Map<ReactionType, List<ReactionUserInfo>> ratingList = {};

Expand Down
12 changes: 6 additions & 6 deletions lib/core/services/implementations/reaction_manager_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import 'package:injector/injector.dart';
import 'package:unn_mobile/core/constants/api_url_strings.dart';
import 'package:unn_mobile/core/constants/rating_list_strings.dart';
import 'package:unn_mobile/core/constants/session_identifier_strings.dart';
import 'package:unn_mobile/core/misc/current_user_sync_storage.dart';
import 'package:unn_mobile/core/misc/http_helper.dart';
import 'package:unn_mobile/core/models/rating_list.dart';
import 'package:unn_mobile/core/services/interfaces/authorisation_service.dart';
import 'package:unn_mobile/core/services/interfaces/reaction_manager.dart';
import 'package:unn_mobile/core/services/interfaces/user_data_provider.dart';

class _KeysForReactionManagerJsonConverter {
static const String data = 'data';
Expand All @@ -23,7 +23,7 @@ class _KeysForReactionManagerJsonConverter {
class ReactionManagerImpl implements ReactionManager {
final _authorisationService =
Injector.appInstance.get<AuthorisationService>();
final _userDataProvider = Injector.appInstance.get<UserDataProvider>();
final _currentUserSync = Injector.appInstance.get<CurrentUserSyncStorage>();

@override
Future<ReactionUserInfo?> addReaction(
Expand Down Expand Up @@ -110,13 +110,13 @@ class ReactionManagerImpl implements ReactionManager {
return null;
}

final userData = await _userDataProvider.getData();

final userData = _currentUserSync.currentUserData;
final photoSrc = jsonMap[_KeysForReactionManagerJsonConverter.photo]
[_KeysForReactionManagerJsonConverter.src];
return ReactionUserInfo(
userData!.bitrixId,
jsonMap[_KeysForReactionManagerJsonConverter.nameFromatted],
jsonMap[_KeysForReactionManagerJsonConverter.photo]
[_KeysForReactionManagerJsonConverter.src],
photoSrc != false ? photoSrc : null,
);
}
}
88 changes: 87 additions & 1 deletion lib/core/viewmodels/feed_screen_view_model.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import 'package:injector/injector.dart';
import 'package:unn_mobile/core/misc/current_user_sync_storage.dart';
import 'package:unn_mobile/core/models/post_with_loaded_info.dart';
import 'package:unn_mobile/core/models/rating_list.dart';
import 'package:unn_mobile/core/services/interfaces/feed_stream_updater_service.dart';
import 'package:unn_mobile/core/services/interfaces/reaction_manager.dart';
import 'package:unn_mobile/core/viewmodels/base_view_model.dart';

class FeedScreenViewModel extends BaseViewModel {
final _feedStreamUpdater = Injector.appInstance.get<FeedUpdaterService>();
final _currentUserSyncStorage =
Injector.appInstance.get<CurrentUserSyncStorage>();
final _reactionManager = Injector.appInstance.get<ReactionManager>();
DateTime? _lastViewedPostDateTime;
List<PostWithLoadedInfo> get posts => _feedStreamUpdater.feedPosts;
bool get isLoadingPosts => _feedStreamUpdater.isBusy;

final pendingReactionChanges = <int>{};

void init() {
_feedStreamUpdater.addListener(() {
notifyListeners();
super.notifyListeners();
});
}

Expand All @@ -27,4 +35,82 @@ class FeedScreenViewModel extends BaseViewModel {
void loadNextPage() {
_feedStreamUpdater.loadNextPage();
}

ReactionType? getReactionToPost(PostWithLoadedInfo post) {
final profileId = _currentUserSyncStorage.currentUserData?.bitrixId;
return profileId != null
? post.ratingList.getReactionByUser(profileId)
: null;
}

void _setReactionToPost(
PostWithLoadedInfo post,
ReactionType? reaction,
) async {
if (post.post.keySigned == null) {
return;
}
final profileId = _currentUserSyncStorage.currentUserData?.bitrixId;
if (profileId == null) {
return;
}
if (reaction == null) {
// Сохраняем то, что сейчас есть в списке
final currentReactionInfo =
post.ratingList.getReactionInfoByUser(profileId);
final currentReaction = post.ratingList.getReactionByUser(profileId);
if (currentReactionInfo == null || currentReaction == null) {
return;
}
pendingReactionChanges.add(post.post.id);
// Временно удаляем реакцию, чтобы показать действие
post.ratingList.removeReaction(profileId);
super.notifyListeners();
if (!await _reactionManager.removeReaction(post.post.keySigned!)) {
// Если реакция не удалилась - восстанавливаем её
post.ratingList.addReactions(currentReaction, [currentReactionInfo]);
super.notifyListeners();
}
pendingReactionChanges.remove(post.post.id);
} else {
pendingReactionChanges.add(post.post.id);
// Добавляем временно, чтобы сразу показать действие
post.ratingList
.addReactions(reaction, [ReactionUserInfo(profileId, '', '')]);
super.notifyListeners();
final reactionUserInfo =
await _reactionManager.addReaction(reaction, post.post.keySigned!);
// Удаляем временную реакцию
post.ratingList.removeReaction(profileId);
if (reactionUserInfo != null) {
// Если реакция реально добавилась - фиксируем это
post.ratingList.addReactions(reaction, [reactionUserInfo]);
}
pendingReactionChanges.remove(post.post.id);
super.notifyListeners();
}
}

void toggleLike(PostWithLoadedInfo post) {
if (pendingReactionChanges.contains(post.post.id)) {
return;
}
if (getReactionToPost(post) != null) {
_setReactionToPost(post, null);
} else {
_setReactionToPost(post, ReactionType.like);
}
super.notifyListeners();
}

void toggleReaction(PostWithLoadedInfo post, ReactionType reaction) async {
if (pendingReactionChanges.contains(post.post.id)) {
return;
}
_setReactionToPost(post, null);
if (getReactionToPost(post) != reaction) {
_setReactionToPost(post, reaction);
}
super.notifyListeners();
}
}
20 changes: 8 additions & 12 deletions lib/core/viewmodels/loading_page_view_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:injector/injector.dart';
import 'package:unn_mobile/core/misc/app_open_tracker.dart';
import 'package:unn_mobile/core/misc/loading_pages.dart';
import 'package:unn_mobile/core/misc/type_of_current_user.dart';
import 'package:unn_mobile/core/misc/current_user_sync_storage.dart';
import 'package:unn_mobile/core/models/loading_page_data.dart';
import 'package:unn_mobile/core/services/interfaces/authorisation_service.dart';
import 'package:unn_mobile/core/services/interfaces/authorisation_refresh_service.dart';
Expand All @@ -21,7 +21,7 @@ enum _TypeScreen {
class LoadingPageViewModel extends BaseViewModel {
final _initializingApplicationService =
Injector.appInstance.get<AuthorisationRefreshService>();
final _typeOfCurrnetUser = Injector.appInstance.get<TypeOfCurrentUser>();
final _typeOfCurrentUser = Injector.appInstance.get<CurrentUserSyncStorage>();
final _gettingProfileOfCurrentUser =
Injector.appInstance.get<GettingProfileOfCurrentUser>();
final _userDataProvider = Injector.appInstance.get<UserDataProvider>();
Expand Down Expand Up @@ -73,16 +73,12 @@ class LoadingPageViewModel extends BaseViewModel {
_userDataProvider.saveData(profile);
}

if (await _userDataProvider.isContained()) {
await _typeOfCurrnetUser.updateTypeOfCurrentUser();
} else {
final profile =
await _gettingProfileOfCurrentUser.getProfileOfCurrentUser();
_userDataProvider.saveData(profile);
if (profile != null && profile.fullUrlPhoto != null) {
DefaultCacheManager().downloadFile(profile.fullUrlPhoto!);
}
_typeOfCurrnetUser.typeOfUser = profile.runtimeType;
await _typeOfCurrentUser.updateCurrentUserInfo();
if (_typeOfCurrentUser.currentUserData != null &&
_typeOfCurrentUser.currentUserData!.fullUrlPhoto != null) {
DefaultCacheManager().downloadFile(
_typeOfCurrentUser.currentUserData!.fullUrlPhoto!,
);
}
}
}
7 changes: 5 additions & 2 deletions lib/core/viewmodels/main_page_view_model.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:injector/injector.dart';
import 'package:unn_mobile/core/misc/current_user_sync_storage.dart';
import 'package:unn_mobile/core/models/student_data.dart';
import 'package:unn_mobile/core/services/interfaces/feed_stream_updater_service.dart';
import 'package:unn_mobile/core/services/interfaces/getting_profile_of_current_user_service.dart';
import 'package:unn_mobile/core/viewmodels/base_view_model.dart';

class MainPageViewModel extends BaseViewModel {
final GettingProfileOfCurrentUser _currentUser =
Injector.appInstance.get<GettingProfileOfCurrentUser>();
final _currentUser = Injector.appInstance.get<GettingProfileOfCurrentUser>();
final _currentUserSyncStorage =
Injector.appInstance.get<CurrentUserSyncStorage>();
int _selectedDrawerItem = 0;
int _selectedBarItem = 1;
bool _isDrawerItemSelected = false;
Expand Down Expand Up @@ -66,6 +68,7 @@ class MainPageViewModel extends BaseViewModel {
Injector.appInstance.get<FeedUpdaterService>().updateFeed();
_currentUser.getProfileOfCurrentUser().then(
(value) {
value = value ?? _currentUserSyncStorage.currentUserData;
if (value == null) {
setState(ViewState.idle);
return;
Expand Down
9 changes: 7 additions & 2 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'package:intl/date_symbol_data_local.dart';
import 'package:unn_mobile/app.dart';
import 'package:unn_mobile/core/misc/app_open_tracker.dart';
import 'package:unn_mobile/core/misc/type_defs.dart';
import 'package:unn_mobile/core/misc/type_of_current_user.dart';
import 'package:unn_mobile/core/misc/current_user_sync_storage.dart';
import 'package:unn_mobile/core/models/online_status_data.dart';
import 'package:unn_mobile/core/services/implementations/auth_data_provider_impl.dart';
import 'package:unn_mobile/core/services/implementations/authorisation_refresh_service_impl.dart';
Expand All @@ -28,6 +28,7 @@ import 'package:unn_mobile/core/services/implementations/getting_grade_book_impl
import 'package:unn_mobile/core/services/implementations/mark_by_subject_provider_impl.dart';
import 'package:unn_mobile/core/services/implementations/offline_schedule_provider_impl.dart';
import 'package:unn_mobile/core/services/implementations/post_with_loaded_info_provider_impl.dart';
import 'package:unn_mobile/core/services/implementations/reaction_manager_impl.dart';
import 'package:unn_mobile/core/services/implementations/schedule_search_history_service_impl.dart';
import 'package:unn_mobile/core/services/implementations/search_id_on_portal_service_impl.dart';
import 'package:unn_mobile/core/services/implementations/storage_service_impl.dart';
Expand All @@ -49,6 +50,7 @@ import 'package:unn_mobile/core/services/interfaces/getting_grade_book.dart';
import 'package:unn_mobile/core/services/interfaces/mark_by_subject_provider.dart';
import 'package:unn_mobile/core/services/interfaces/offline_schedule_provider.dart';
import 'package:unn_mobile/core/services/interfaces/post_with_loaded_info_provider.dart';
import 'package:unn_mobile/core/services/interfaces/reaction_manager.dart';
import 'package:unn_mobile/core/services/interfaces/schedule_search_history_service.dart';
import 'package:unn_mobile/core/services/interfaces/search_id_on_portal_service.dart';
import 'package:unn_mobile/core/services/interfaces/storage_service.dart';
Expand Down Expand Up @@ -126,7 +128,9 @@ void registerDependencies() {
injector.registerSingleton<FeedUpdaterService>(
() => FeedStreamUpdaterServiceImpl(),
);
injector.registerSingleton<TypeOfCurrentUser>(() => TypeOfCurrentUser());
injector.registerSingleton<CurrentUserSyncStorage>(
() => CurrentUserSyncStorage(),
);
injector.registerSingleton<PostWithLoadedInfoProvider>(
() => PostWithLoadedInfoProviderImpl(),
);
Expand All @@ -146,6 +150,7 @@ void registerDependencies() {
() => MarkBySubjectProviderImpl(),
);
injector.registerSingleton<AppOpenTracker>(() => AppOpenTracker());
injector.registerSingleton<ReactionManager>(() => ReactionManagerImpl());

injector.registerDependency(() => LoadingPageViewModel());
injector.registerDependency(() => AuthPageViewModel());
Expand Down
Loading

0 comments on commit 0e79003

Please sign in to comment.