Skip to content

Commit

Permalink
feat(status): add online/offline status in player detail
Browse files Browse the repository at this point in the history
User can now see the player status and active match button will lit up if player is online

resolves #275
  • Loading branch information
tusharlock10 committed May 4, 2022
1 parent ee9419c commit 9280cc5
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 64 deletions.
6 changes: 5 additions & 1 deletion lib/api/players/requests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,15 @@ abstract class PlayersRequests {

static Future<responses.PlayerStatusResponse?> playerStatus({
required String playerId,
bool onlyStatus = false,
}) async {
try {
final response = await utilities.api.get<Map<String, dynamic>>(
constants.Urls.playerStatus,
queryParameters: {'playerId': playerId},
queryParameters: {
'playerId': playerId,
'onlyStatus': onlyStatus,
},
);
if (response.data != null) {
return responses.PlayerStatusResponse.fromJson(response.data!);
Expand Down
6 changes: 5 additions & 1 deletion lib/providers/players.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@ class _PlayersNotifier extends ChangeNotifier {
Future<void> getPlayerStatus({
required String playerId,
bool forceUpdate = false,
bool onlyStatus = false,
}) async {
if (!forceUpdate) {
isLoadingPlayerStatus = true;
utilities.postFrameCallback(notifyListeners);
}

playerStatus = await api.PlayersRequests.playerStatus(playerId: playerId);
playerStatus = await api.PlayersRequests.playerStatus(
playerId: playerId,
onlyStatus: onlyStatus,
);

if (!forceUpdate) isLoadingPlayerStatus = false;
notifyListeners();
Expand Down
23 changes: 19 additions & 4 deletions lib/screens/player_detail/player_detail.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ class PlayerDetail extends HookConsumerWidget {
if (player == null) {
// fetch playerData from server
playersProvider.getPlayerData(forceUpdate: false);
// fetch playerStatus from server
playersProvider.getPlayerStatus(
playerId: playerId,
onlyStatus: true,
);
}

return;
Expand Down Expand Up @@ -67,10 +72,20 @@ class PlayerDetail extends HookConsumerWidget {
() async {
if (playerId == null) return;

return matchesProvider.getPlayerMatches(
playerId: playerId,
forceUpdate: true,
);
final futures = [
playersProvider.getPlayerStatus(
playerId: playerId,
forceUpdate: true,
onlyStatus: true,
),
matchesProvider.getPlayerMatches(
playerId: playerId,
forceUpdate: true,
),
];
await Future.wait(futures);

return;
},
[playerId],
);
Expand Down
122 changes: 64 additions & 58 deletions lib/screens/player_detail/player_detail_header.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:paladinsedge/providers/index.dart' as providers;
import 'package:paladinsedge/screens/index.dart' as screens;
import 'package:paladinsedge/screens/player_detail/player_detail_status_indicator.dart';
import 'package:paladinsedge/widgets/index.dart' as widgets;

class PlayerDetailHeader extends HookConsumerWidget {
Expand All @@ -16,10 +17,16 @@ class PlayerDetailHeader extends HookConsumerWidget {
final playersProvider = ref.read(providers.players);
final friendsProvider = ref.read(providers.friends);
final player = ref.watch(providers.players.select((_) => _.playerData));
final playerStatus =
ref.watch(providers.players.select((_) => _.playerStatus));

// Variables
final textTheme = Theme.of(context).textTheme;
final scaffoldBackgroundColor = Theme.of(context).scaffoldBackgroundColor;
final status = playerStatus?.status;
final isOnline = status?.toLowerCase() != "offline" &&
status?.toLowerCase() != "unknown" &&
status != null;

// Methods
final onPressActiveMatch = useCallback(
Expand Down Expand Up @@ -59,65 +66,64 @@ class PlayerDetailHeader extends HookConsumerWidget {
),
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
child: Row(
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
widgets.ElevatedAvatar(
imageUrl: player.avatarUrl,
imageBlurHash: player.avatarBlurHash,
size: 42,
borderRadius: 10,
),
const SizedBox(width: 10),
Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
widgets.FastImage(
imageUrl: player.ranked.rankIconUrl,
height: 36,
width: 36,
),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
player.ranked.rankName,
style: textTheme.bodyText2
?.copyWith(fontSize: 14),
),
Text(
'${player.ranked.points} TP',
style: textTheme.bodyText1
?.copyWith(fontSize: 12),
),
],
),
],
),
const SizedBox(height: 5),
Row(
children: [
widgets.Button(
label: 'Friends',
color: Colors.green,
onPressed: onPressFriends,
),
const SizedBox(width: 10),
widgets.Button(
label: 'Active Match',
onPressed: onPressActiveMatch,
),
],
),
],
),
],
widgets.ElevatedAvatar(
imageUrl: player.avatarUrl,
imageBlurHash: player.avatarBlurHash,
size: 42,
borderRadius: 10,
),
const SizedBox(width: 10),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
widgets.FastImage(
imageUrl: player.ranked.rankIconUrl,
height: 36,
width: 36,
),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
player.ranked.rankName,
style: textTheme.bodyText2
?.copyWith(fontSize: 14),
),
Text(
'${player.ranked.points} TP',
style: textTheme.bodyText1
?.copyWith(fontSize: 12),
),
],
),
const PlayerDetailStatusIndicator(),
],
),
const SizedBox(height: 5),
Row(
children: [
widgets.Button(
label: 'Friends',
onPressed: onPressFriends,
),
const SizedBox(width: 10),
widgets.Button(
label: 'Active Match',
disabled: !isOnline,
onPressed: onPressActiveMatch,
color: Colors.green,
),
],
),
],
),
),
],
),
Expand Down
109 changes: 109 additions & 0 deletions lib/screens/player_detail/player_detail_status_indicator.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:jiffy/jiffy.dart';
import 'package:paladinsedge/providers/index.dart' as providers;
import 'package:paladinsedge/widgets/index.dart' as widgets;

class PlayerDetailStatusIndicator extends HookConsumerWidget {
const PlayerDetailStatusIndicator({Key? key}) : super(key: key);

@override
Widget build(BuildContext context, WidgetRef ref) {
// Providers
final player = ref.watch(providers.players.select((_) => _.playerData));
final isLoadingPlayerStatus =
ref.watch(providers.players.select((_) => _.isLoadingPlayerStatus));
final playerStatus =
ref.watch(providers.players.select((_) => _.playerStatus));

// Variables
final status = playerStatus?.status;
final isOnline = status?.toLowerCase() != "offline" &&
status?.toLowerCase() != "unknown" &&
status != null;
final isUnknown = status?.toLowerCase() == "unknown" || status == null;
final textTheme = Theme.of(context).textTheme;

// Methods
final getLastSeen = useCallback(
() {
if (player == null) return '';

final lastLoginDate = player.lastLoginDate;
final duration = DateTime.now().difference(lastLoginDate);
if (duration > const Duration(days: 1)) {
return Jiffy(lastLoginDate).yMMMd;
}

return Jiffy(lastLoginDate).fromNow();
},
[player],
);

return Expanded(
child: Align(
alignment: Alignment.centerRight,
child: Padding(
padding: const EdgeInsets.only(right: 10),
child: isLoadingPlayerStatus || status == null
? Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
widgets.LoadingIndicator(
size: 12,
lineWidth: 1.2,
color: textTheme.bodyText1?.color,
),
const SizedBox(width: 5),
Text(
'Status',
style: textTheme.bodyText1?.copyWith(fontSize: 14),
),
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
SizedBox(
height: 10,
width: 10,
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(
Radius.circular(
5,
),
),
color: isOnline
? Colors.green
: isUnknown
? Colors.orange
: Colors.red,
),
),
),
const SizedBox(width: 5),
Text(
isOnline
? 'Online'
: isUnknown
? 'Unknown'
: 'Offline',
),
],
),
Text(
isOnline ? status : getLastSeen(),
style: textTheme.bodyText1?.copyWith(fontSize: 12),
),
],
),
),
),
);
}
}
2 changes: 2 additions & 0 deletions lib/screens/search/search_history.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:jiffy/jiffy.dart';
import 'package:paladinsedge/providers/index.dart' as providers;
import 'package:paladinsedge/screens/index.dart' as screens;
import 'package:paladinsedge/utilities/index.dart' as utilities;
import 'package:timer_builder/timer_builder.dart';

class SearchHistory extends HookConsumerWidget {
Expand All @@ -23,6 +24,7 @@ class SearchHistory extends HookConsumerWidget {
final onTap = useCallback(
(String playerId) {
playersProvider.setPlayerId(playerId);
utilities.unFocusKeyboard(context);
Navigator.of(context).pushNamed(screens.PlayerDetail.routeName);
},
[],
Expand Down

0 comments on commit 9280cc5

Please sign in to comment.