Compare commits

..

2 Commits

Author SHA1 Message Date
d764b042fe Shows account own activities on account page 2025-11-02 16:59:58 +08:00
a76b97d1d2 💄 Shows listening activities are from spotfiy 2025-11-02 16:55:16 +08:00
2 changed files with 246 additions and 188 deletions

View File

@@ -8,6 +8,7 @@ import 'package:island/pods/userinfo.dart';
import 'package:island/screens/notification.dart'; import 'package:island/screens/notification.dart';
import 'package:island/services/responsive.dart'; import 'package:island/services/responsive.dart';
import 'package:island/widgets/account/account_name.dart'; import 'package:island/widgets/account/account_name.dart';
import 'package:island/widgets/account/activity_presence.dart';
import 'package:island/widgets/account/status.dart'; import 'package:island/widgets/account/status.dart';
import 'package:island/widgets/account/leveling_progress.dart'; import 'package:island/widgets/account/leveling_progress.dart';
import 'package:island/widgets/alert.dart'; import 'package:island/widgets/alert.dart';
@@ -177,7 +178,21 @@ class AccountScreen extends HookConsumerWidget {
).padding(horizontal: 8), ).padding(horizontal: 8),
Card( Card(
margin: EdgeInsets.zero, margin: EdgeInsets.zero,
child: AccountStatusCreationWidget(uname: user.value!.name), child: Column(
children: [
AccountStatusCreationWidget(uname: user.value!.name),
ActivityPresenceWidget(
uname: user.value!.name,
isCompact: true,
compactPadding: const EdgeInsets.only(
left: 16,
right: 16,
bottom: 8,
top: 4,
),
),
],
),
).padding(horizontal: 12, bottom: 4), ).padding(horizontal: 12, bottom: 4),
LevelingProgressCard( LevelingProgressCard(
isCompact: true, isCompact: true,
@@ -251,7 +266,9 @@ class AccountScreen extends HookConsumerWidget {
).padding(horizontal: 12), ).padding(horizontal: 12),
const SizedBox.shrink(), const SizedBox.shrink(),
ConstrainedBox( ConstrainedBox(
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width), constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width,
),
child: LayoutBuilder( child: LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
const minWidth = 160.0; const minWidth = 160.0;
@@ -312,14 +329,23 @@ class AccountScreen extends HookConsumerWidget {
if (availableWidth > totalMin) { if (availableWidth > totalMin) {
return Row( return Row(
spacing: 8, spacing: 8,
children: children.map((child) => Expanded(child: child)).toList(), children:
children
.map((child) => Expanded(child: child))
.toList(),
).padding(horizontal: 12).height(48); ).padding(horizontal: 12).height(48);
} else { } else {
return SingleChildScrollView( return SingleChildScrollView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
child: Row( child: Row(
spacing: 8, spacing: 8,
children: children.map((child) => SizedBox(width: minWidth, child: child)).toList(), children:
children
.map(
(child) =>
SizedBox(width: minWidth, child: child),
)
.toList(),
).padding(horizontal: 12), ).padding(horizontal: 12),
).height(48); ).height(48);
} }

View File

@@ -393,9 +393,11 @@ class _ActivityPresenceWidgetState extends State<ActivityPresenceWidget>
], ],
).opacity(0.75).padding(horizontal: 16, bottom: 8), ).opacity(0.75).padding(horizontal: 16, bottom: 8),
...activities.map((activity) { ...activities.map((activity) {
final dcImages = _buildImages(ref, activity); final images = _buildImages(ref, activity);
return Card( return Stack(
children: [
Card(
elevation: 0, elevation: 0,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
side: BorderSide( side: BorderSide(
@@ -409,11 +411,12 @@ class _ActivityPresenceWidgetState extends State<ActivityPresenceWidget>
title: Column( title: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (dcImages.isNotEmpty) if (images.isNotEmpty)
Row( Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment:
CrossAxisAlignment.end,
spacing: 8, spacing: 8,
children: dcImages, children: images,
).padding(vertical: 4), ).padding(vertical: 4),
Row( Row(
spacing: 2, spacing: 2,
@@ -431,7 +434,9 @@ class _ActivityPresenceWidgetState extends State<ActivityPresenceWidget>
onPressed: () { onPressed: () {
launchUrlString(activity.titleUrl!); launchUrlString(activity.titleUrl!);
}, },
icon: const Icon(Symbols.launch_rounded), icon: const Icon(
Symbols.launch_rounded,
),
iconSize: 16, iconSize: 16,
padding: EdgeInsets.all(4), padding: EdgeInsets.all(4),
constraints: const BoxConstraints( constraints: const BoxConstraints(
@@ -468,11 +473,13 @@ class _ActivityPresenceWidgetState extends State<ActivityPresenceWidget>
builder: (context, snapshot) { builder: (context, snapshot) {
final now = DateTime.now(); final now = DateTime.now();
final meta = final meta =
activity.meta as Map<String, dynamic>; activity.meta
as Map<String, dynamic>;
final progressMs = final progressMs =
meta['progress_ms'] as int? ?? 0; meta['progress_ms'] as int? ?? 0;
final durationMs = final durationMs =
meta['track_duration_ms'] as int? ?? 1; meta['track_duration_ms'] as int? ??
1;
final elapsed = final elapsed =
now now
.difference(activity.createdAt) .difference(activity.createdAt)
@@ -488,7 +495,9 @@ class _ActivityPresenceWidgetState extends State<ActivityPresenceWidget>
begin: _startProgress, begin: _startProgress,
end: _endProgress, end: _endProgress,
).animate(_progressController); ).animate(_progressController);
_progressController.forward(from: 0.0); _progressController.forward(
from: 0.0,
);
} }
return AnimatedBuilder( return AnimatedBuilder(
animation: _progressAnimation, animation: _progressAnimation,
@@ -503,7 +512,8 @@ class _ActivityPresenceWidgetState extends State<ActivityPresenceWidget>
final currentSec = final currentSec =
(animatedProgressMs % 60000) ~/ (animatedProgressMs % 60000) ~/
1000; 1000;
final totalMin = durationMs ~/ 60000; final totalMin =
durationMs ~/ 60000;
final totalSec = final totalSec =
(durationMs % 60000) ~/ 1000; (durationMs % 60000) ~/ 1000;
return Column( return Column(
@@ -516,11 +526,12 @@ class _ActivityPresenceWidgetState extends State<ActivityPresenceWidget>
backgroundColor: backgroundColor:
Colors.grey.shade300, Colors.grey.shade300,
trackGap: 0, trackGap: 0,
stopIndicatorColor: Colors.green, stopIndicatorColor:
valueColor:
AlwaysStoppedAnimation<Color>(
Colors.green, Colors.green,
), valueColor:
AlwaysStoppedAnimation<
Color
>(Colors.green),
).padding(top: 3), ).padding(top: 3),
Text( Text(
'${currentMin.toString().padLeft(2, '0')}:${currentSec.toString().padLeft(2, '0')} / ${totalMin.toString().padLeft(2, '0')}:${totalSec.toString().padLeft(2, '0')}', '${currentMin.toString().padLeft(2, '0')}:${currentSec.toString().padLeft(2, '0')} / ${totalMin.toString().padLeft(2, '0')}:${totalSec.toString().padLeft(2, '0')}',
@@ -549,10 +560,12 @@ class _ActivityPresenceWidgetState extends State<ActivityPresenceWidget>
final hours = duration.inHours final hours = duration.inHours
.toString() .toString()
.padLeft(2, '0'); .padLeft(2, '0');
final minutes = (duration.inMinutes % 60) final minutes = (duration.inMinutes %
60)
.toString() .toString()
.padLeft(2, '0'); .padLeft(2, '0');
final seconds = (duration.inSeconds % 60) final seconds = (duration.inSeconds %
60)
.toString() .toString()
.padLeft(2, '0'); .padLeft(2, '0');
return Text( return Text(
@@ -564,12 +577,16 @@ class _ActivityPresenceWidgetState extends State<ActivityPresenceWidget>
Row( Row(
spacing: 2, spacing: 2,
children: [ children: [
Flexible(child: Text(activity.subtitle!)), Flexible(
child: Text(activity.subtitle!),
),
if (activity.titleUrl != null && if (activity.titleUrl != null &&
activity.titleUrl!.isNotEmpty) activity.titleUrl!.isNotEmpty)
IconButton( IconButton(
onPressed: () { onPressed: () {
launchUrlString(activity.titleUrl!); launchUrlString(
activity.titleUrl!,
);
}, },
icon: const Icon( icon: const Icon(
Symbols.launch_rounded, Symbols.launch_rounded,
@@ -588,7 +605,22 @@ class _ActivityPresenceWidgetState extends State<ActivityPresenceWidget>
], ],
), ),
), ),
).padding(horizontal: 8); ).padding(horizontal: 8),
if (activity.manualId == 'spotify')
Positioned(
top: 16,
right: 24,
child: Tooltip(
message: 'Listening on Spotify',
child: Image.asset(
'assets/images/oidc/spotify.png',
width: 24,
height: 24,
),
),
),
],
);
}), }),
], ],
).padding(horizontal: 8, top: 8, bottom: 16), ).padding(horizontal: 8, top: 8, bottom: 16),