add web session indicator to profile card, clean up cookie extraction

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Tommy Chow 2026-03-08 18:40:43 -07:00
parent f27de6dc3d
commit d048875490
4 changed files with 54 additions and 10 deletions

View file

@ -11,7 +11,6 @@ import 'package:frosty/models/stream.dart';
import 'package:frosty/screens/channel/video/video_player_interface.dart';
import 'package:frosty/screens/settings/stores/auth_store.dart';
import 'package:frosty/screens/settings/stores/settings_store.dart';
import 'package:frosty/services/cookie_extractor.dart';
import 'package:mobx/mobx.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -102,10 +101,8 @@ abstract class NativeVideoStoreBase with Store implements VideoPlayerInterface {
@action
Future<void> _initPlayer() async {
try {
// Prefer web cookie token (works with web Client-ID) for ad-free playback.
// Fall back to direct cookie extraction if AuthStore hasn't resolved it yet.
var authToken = authStore.gqlToken;
authToken ??= await CookieExtractor.extractTwitchAuthToken();
// Use web cookie token (works with web Client-ID) for ad-free playback.
final authToken = authStore.gqlToken;
late final PlaybackAccessToken token;
try {
token = await twitchGqlApi.getPlaybackAccessToken(

View file

@ -39,13 +39,63 @@ class ProfileCard extends StatelessWidget {
);
}
if (authStore.isLoggedIn && authStore.user.details != null) {
final hasToken = authStore.gqlToken != null;
return ListTile(
leading: ProfilePicture(
userLogin: authStore.user.details!.login,
radius: 12,
),
title: Text(authStore.user.details!.displayName),
trailing: const Icon(Icons.chevron_right_rounded),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
tooltip: hasToken
? 'Web session linked'
: 'Web session not linked',
icon: Icon(
hasToken
? Icons.check_circle_outline_rounded
: Icons.link_off_rounded,
size: 20,
color: hasToken ? Colors.green : null,
),
onPressed: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Web session'),
content: Text(
hasToken
? 'Your Twitch web session is linked. When using the native player, ads will be avoided on channels where you have a subscription or Twitch Turbo.'
: 'Your Twitch web session is not linked. Log in again to avoid ads when using the native player on channels where you have a subscription or Twitch Turbo.',
),
actions: [
if (!hasToken)
TextButton(
onPressed: () {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LoginWebView(),
),
);
},
child: const Text('Log in'),
),
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('OK'),
),
],
),
);
},
),
const Icon(Icons.chevron_right_rounded),
],
),
onTap: () => _showAccountOptionsModalBottomSheet(context),
);
}

View file

@ -275,9 +275,6 @@ abstract class AuthBase with Store {
}
}
// Try extracting a fresh GQL token from the WebView cookie store.
if (_isLoggedIn) await _extractGqlToken();
FirebaseCrashlytics.instance.setCustomKey('is_logged_in', _isLoggedIn);
_error = null;
} catch (e) {

View file

@ -28,7 +28,7 @@ class VideoSettings extends StatelessWidget {
SettingsListSwitch(
title: 'Native player (experimental)',
subtitle: const Text(
'Uses a native video player with improved picture-in-picture.',
'Native video player with auto picture-in-picture and quality selection.',
),
value: settingsStore.useNativePlayer,
onChanged: (newValue) =>