Skip to content

Commit 289f672

Browse files
authored
refactor: contact presence view (#859)
1 parent 665cde9 commit 289f672

10 files changed

Lines changed: 426 additions & 92 deletions

lib/features/contact/widgets/presence_info_view.dart

Lines changed: 83 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
import 'package:flutter/material.dart';
2-
1+
import 'package:clock/clock.dart';
32
import 'package:intl/intl.dart';
43

4+
import 'package:flutter/material.dart';
5+
56
import 'package:webtrit_phone/l10n/l10n.dart';
67
import 'package:webtrit_phone/models/models.dart';
8+
import 'package:webtrit_phone/extensions/extensions.dart';
9+
import 'package:webtrit_phone/widgets/widgets.dart';
710

811
class PresenceInfoView extends StatelessWidget {
912
const PresenceInfoView({required this.presenceInfo, super.key});
@@ -23,87 +26,89 @@ class PresenceInfoView extends StatelessWidget {
2326
style: Theme.of(context).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.bold),
2427
),
2528
for (final info in presenceInfo)
26-
Column(
27-
crossAxisAlignment: CrossAxisAlignment.stretch,
28-
children: [
29-
Text(
30-
'${l10n.presence_infoView_device} ${presenceInfo.indexOf(info) + 1}',
31-
style: Theme.of(context).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.bold),
32-
),
33-
Row(
34-
mainAxisAlignment: MainAxisAlignment.start,
29+
Builder(
30+
builder: (context) {
31+
final maybeActivityText = info.activities.isNotEmpty
32+
? info.activities.first.l10n(l10n)
33+
: (info.available ? l10n.presence_infoView_available_true : l10n.presence_infoView_available_false);
34+
35+
final shouldDisplayNote = info.note.isNotEmpty && info.note.trim() != maybeActivityText;
36+
37+
return Column(
38+
crossAxisAlignment: CrossAxisAlignment.stretch,
39+
spacing: 2,
3540
children: [
36-
Text(l10n.presence_infoView_available, style: Theme.of(context).textTheme.bodyMedium),
37-
const SizedBox(width: 4),
38-
Text(
39-
info.available ? l10n.presence_infoView_available_true : l10n.presence_infoView_available_false,
40-
style: Theme.of(context).textTheme.bodyMedium,
41-
),
42-
],
43-
),
44-
if (info.note.isNotEmpty)
45-
Row(
46-
mainAxisAlignment: MainAxisAlignment.start,
47-
children: [
48-
Text(l10n.presence_infoView_note, style: Theme.of(context).textTheme.bodyMedium),
49-
const SizedBox(width: 4),
50-
Text(info.note, style: Theme.of(context).textTheme.bodyMedium),
51-
],
52-
),
53-
if (info.activities.isNotEmpty)
54-
Row(
55-
mainAxisAlignment: MainAxisAlignment.start,
56-
children: [
57-
Text(l10n.presence_infoView_activity, style: Theme.of(context).textTheme.bodyMedium),
58-
const SizedBox(width: 4),
59-
Text(info.activities.first.name, style: Theme.of(context).textTheme.bodyMedium),
60-
],
61-
),
62-
if (info.statusIcon != null && info.statusIcon!.isNotEmpty)
63-
Row(
64-
mainAxisAlignment: MainAxisAlignment.start,
65-
children: [
66-
Text(l10n.presence_infoView_statusIcon, style: Theme.of(context).textTheme.bodyMedium),
67-
const SizedBox(width: 4),
68-
Text(info.statusIcon!, style: Theme.of(context).textTheme.bodyMedium),
69-
],
70-
),
71-
if (info.timeOffsetMin != null)
72-
Row(
73-
mainAxisAlignment: MainAxisAlignment.start,
74-
children: [
75-
Text(l10n.presence_infoView_timeZone, style: Theme.of(context).textTheme.bodyMedium),
76-
const SizedBox(width: 4),
41+
if (presenceInfo.length > 1)
7742
Text(
78-
'UTC${info.timeOffsetMin! >= 0 ? '+' : ''}${(info.timeOffsetMin! ~/ 60)}',
79-
style: Theme.of(context).textTheme.bodyMedium,
43+
'${l10n.presence_infoView_device} ${presenceInfo.indexOf(info) + 1}',
44+
style: Theme.of(context).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.bold),
45+
),
46+
Row(
47+
children: [
48+
SizedBox(
49+
width: 16,
50+
height: 16,
51+
child: SipPresenceIndicator(
52+
presenceInfo: presenceInfo,
53+
presenceRect: Rect.fromLTWH(0, 0, 16, 16),
54+
),
55+
),
56+
const SizedBox(width: 4),
57+
Text(maybeActivityText, style: Theme.of(context).textTheme.bodySmall),
58+
],
59+
),
60+
61+
if (shouldDisplayNote)
62+
Row(
63+
mainAxisAlignment: MainAxisAlignment.start,
64+
children: [
65+
Flexible(child: Text(info.note, style: Theme.of(context).textTheme.bodySmall)),
66+
const SizedBox(width: 4),
67+
68+
if (info.statusIcon != null && info.statusIcon!.isNotEmpty)
69+
Text(info.statusIcon!, style: Theme.of(context).textTheme.bodySmall),
70+
],
8071
),
81-
],
82-
),
8372

84-
if (info.timestamp != null)
85-
Row(
86-
mainAxisAlignment: MainAxisAlignment.start,
87-
children: [
88-
Text(l10n.presence_infoView_updated, style: Theme.of(context).textTheme.bodyMedium),
89-
const SizedBox(width: 4),
90-
Text(
91-
DateFormat.yMd().add_Hm().format(info.timestamp!.toLocal()),
92-
style: Theme.of(context).textTheme.bodyMedium,
73+
if (info.timeOffsetMin != null)
74+
Row(
75+
mainAxisAlignment: MainAxisAlignment.start,
76+
children: [
77+
Text(l10n.presence_infoView_localTime, style: Theme.of(context).textTheme.bodySmall),
78+
const SizedBox(width: 4),
79+
Text(
80+
DateFormat.Hm().format(clock.now().toUtc().add(Duration(minutes: info.timeOffsetMin ?? 0))),
81+
style: Theme.of(context).textTheme.bodySmall,
82+
),
83+
Text(
84+
' (UTC${info.timeOffsetMin! >= 0 ? '+' : ''}${(info.timeOffsetMin! ~/ 60)})',
85+
style: Theme.of(context).textTheme.bodySmall,
86+
),
87+
],
9388
),
94-
],
95-
),
96-
if (info.device != null && info.device!.isNotEmpty)
97-
Row(
98-
mainAxisAlignment: MainAxisAlignment.start,
99-
children: [
100-
Text(l10n.presence_infoView_client, style: Theme.of(context).textTheme.bodyMedium),
101-
const SizedBox(width: 4),
102-
Text(info.device!, style: Theme.of(context).textTheme.bodyMedium),
103-
],
104-
),
105-
// const Divider(),
106-
],
89+
90+
if (info.timestamp != null)
91+
Row(
92+
mainAxisAlignment: MainAxisAlignment.start,
93+
children: [
94+
Text(l10n.presence_infoView_updated, style: Theme.of(context).textTheme.bodySmall),
95+
const SizedBox(width: 4),
96+
97+
AgoTicker(
98+
timestamp: info.timestamp!,
99+
builder: (ago) => Text(ago, style: Theme.of(context).textTheme.bodySmall),
100+
),
101+
],
102+
),
103+
if (info.device != null && info.device!.isNotEmpty)
104+
Row(
105+
mainAxisAlignment: MainAxisAlignment.start,
106+
children: [Text(info.device!, style: Theme.of(context).textTheme.bodySmall)],
107+
),
108+
// const Divider(),
109+
],
110+
);
111+
},
107112
),
108113
],
109114
),

lib/l10n/app_localizations.g.dart

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2505,13 +2505,13 @@ abstract class AppLocalizations {
25052505
/// No description provided for @presence_infoView_available_false.
25062506
///
25072507
/// In en, this message translates to:
2508-
/// **'No'**
2508+
/// **'Unreachable'**
25092509
String get presence_infoView_available_false;
25102510

25112511
/// No description provided for @presence_infoView_available_true.
25122512
///
25132513
/// In en, this message translates to:
2514-
/// **'Yes'**
2514+
/// **'Available'**
25152515
String get presence_infoView_available_true;
25162516

25172517
/// No description provided for @presence_infoView_client.
@@ -2526,6 +2526,12 @@ abstract class AppLocalizations {
25262526
/// **'Device:'**
25272527
String get presence_infoView_device;
25282528

2529+
/// No description provided for @presence_infoView_localTime.
2530+
///
2531+
/// In en, this message translates to:
2532+
/// **'Local Time:'**
2533+
String get presence_infoView_localTime;
2534+
25292535
/// No description provided for @presence_infoView_note.
25302536
///
25312537
/// In en, this message translates to:
@@ -4301,6 +4307,30 @@ abstract class AppLocalizations {
43014307
/// In en, this message translates to:
43024308
/// **'Try again'**
43034309
String get webview_sslError_tryAgain;
4310+
4311+
/// Elapsed time relative to now, shown in seconds.
4312+
///
4313+
/// In en, this message translates to:
4314+
/// **'{seconds, plural, one{{seconds} second ago} other{{seconds} seconds ago}}'**
4315+
String agoTicker_secondsAgo(int seconds);
4316+
4317+
/// Elapsed time relative to now, shown in minutes.
4318+
///
4319+
/// In en, this message translates to:
4320+
/// **'{minutes, plural, one{{minutes} minute ago} other{{minutes} minutes ago}}'**
4321+
String agoTicker_minutesAgo(int minutes);
4322+
4323+
/// Elapsed time relative to now, shown in hours.
4324+
///
4325+
/// In en, this message translates to:
4326+
/// **'{hours, plural, one{{hours} hour ago} other{{hours} hours ago}}'**
4327+
String agoTicker_hoursAgo(int hours);
4328+
4329+
/// Elapsed time relative to now, shown in days.
4330+
///
4331+
/// In en, this message translates to:
4332+
/// **'{days, plural, one{{days} day ago} other{{days} days ago}}'**
4333+
String agoTicker_daysAgo(int days);
43044334
}
43054335

43064336
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {

lib/l10n/app_localizations_en.g.dart

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,17 +1304,20 @@ class AppLocalizationsEn extends AppLocalizations {
13041304
String get presence_infoView_available => 'Available:';
13051305

13061306
@override
1307-
String get presence_infoView_available_false => 'No';
1307+
String get presence_infoView_available_false => 'Unreachable';
13081308

13091309
@override
1310-
String get presence_infoView_available_true => 'Yes';
1310+
String get presence_infoView_available_true => 'Available';
13111311

13121312
@override
13131313
String get presence_infoView_client => 'Client:';
13141314

13151315
@override
13161316
String get presence_infoView_device => 'Device:';
13171317

1318+
@override
1319+
String get presence_infoView_localTime => 'Local Time:';
1320+
13181321
@override
13191322
String get presence_infoView_note => 'Note:';
13201323

@@ -2278,4 +2281,38 @@ class AppLocalizationsEn extends AppLocalizations {
22782281

22792282
@override
22802283
String get webview_sslError_tryAgain => 'Try again';
2284+
2285+
@override
2286+
String agoTicker_secondsAgo(int seconds) {
2287+
String _temp0 = intl.Intl.pluralLogic(
2288+
seconds,
2289+
locale: localeName,
2290+
other: '$seconds seconds ago',
2291+
one: '$seconds second ago',
2292+
);
2293+
return '$_temp0';
2294+
}
2295+
2296+
@override
2297+
String agoTicker_minutesAgo(int minutes) {
2298+
String _temp0 = intl.Intl.pluralLogic(
2299+
minutes,
2300+
locale: localeName,
2301+
other: '$minutes minutes ago',
2302+
one: '$minutes minute ago',
2303+
);
2304+
return '$_temp0';
2305+
}
2306+
2307+
@override
2308+
String agoTicker_hoursAgo(int hours) {
2309+
String _temp0 = intl.Intl.pluralLogic(hours, locale: localeName, other: '$hours hours ago', one: '$hours hour ago');
2310+
return '$_temp0';
2311+
}
2312+
2313+
@override
2314+
String agoTicker_daysAgo(int days) {
2315+
String _temp0 = intl.Intl.pluralLogic(days, locale: localeName, other: '$days days ago', one: '$days day ago');
2316+
return '$_temp0';
2317+
}
22812318
}

lib/l10n/app_localizations_it.g.dart

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,17 +1318,20 @@ class AppLocalizationsIt extends AppLocalizations {
13181318
String get presence_infoView_available => 'Disponibile:';
13191319

13201320
@override
1321-
String get presence_infoView_available_false => 'No';
1321+
String get presence_infoView_available_false => 'Non raggiungibile';
13221322

13231323
@override
1324-
String get presence_infoView_available_true => '';
1324+
String get presence_infoView_available_true => 'Disponibile';
13251325

13261326
@override
13271327
String get presence_infoView_client => 'Client:';
13281328

13291329
@override
13301330
String get presence_infoView_device => 'Dispositivo:';
13311331

1332+
@override
1333+
String get presence_infoView_localTime => 'Ora locale:';
1334+
13321335
@override
13331336
String get presence_infoView_note => 'Nota:';
13341337

@@ -2300,4 +2303,38 @@ class AppLocalizationsIt extends AppLocalizations {
23002303

23012304
@override
23022305
String get webview_sslError_tryAgain => 'Riprova';
2306+
2307+
@override
2308+
String agoTicker_secondsAgo(int seconds) {
2309+
String _temp0 = intl.Intl.pluralLogic(
2310+
seconds,
2311+
locale: localeName,
2312+
other: '$seconds secondi fa',
2313+
one: '$seconds secondo fa',
2314+
);
2315+
return '$_temp0';
2316+
}
2317+
2318+
@override
2319+
String agoTicker_minutesAgo(int minutes) {
2320+
String _temp0 = intl.Intl.pluralLogic(
2321+
minutes,
2322+
locale: localeName,
2323+
other: '$minutes minuti fa',
2324+
one: '$minutes minuto fa',
2325+
);
2326+
return '$_temp0';
2327+
}
2328+
2329+
@override
2330+
String agoTicker_hoursAgo(int hours) {
2331+
String _temp0 = intl.Intl.pluralLogic(hours, locale: localeName, other: '$hours ore fa', one: '$hours ora fa');
2332+
return '$_temp0';
2333+
}
2334+
2335+
@override
2336+
String agoTicker_daysAgo(int days) {
2337+
String _temp0 = intl.Intl.pluralLogic(days, locale: localeName, other: '$days giorni fa', one: '$days giorno fa');
2338+
return '$_temp0';
2339+
}
23032340
}

0 commit comments

Comments
 (0)