Вход в кАналы по ссылке, возможность на них подписаться, отписаться пока нельзя sosi

This commit is contained in:
jganenok
2025-11-27 15:12:30 +07:00
parent 1007a053fd
commit 8991cd5bb8
4 changed files with 584 additions and 58 deletions

View File

@@ -259,8 +259,26 @@ class _HomeScreenState extends State<HomeScreen> {
}
void _handleJoinLink(Uri uri) {
if (uri.host == 'max.ru' && uri.path.startsWith('/join/')) {
final String fullLink = uri.toString();
if (uri.host != 'max.ru') return;
String fullLink = uri.toString();
// На всякий случай убираем возможный префикс '@' перед ссылкой
if (fullLink.startsWith('@')) {
fullLink = fullLink.substring(1);
}
final bool isGroupLink = uri.path.startsWith('/join/');
final bool isChannelLink =
!isGroupLink &&
uri.pathSegments.isNotEmpty &&
uri.pathSegments.first.startsWith('id');
if (!isGroupLink && !isChannelLink) {
return;
}
if (isGroupLink) {
final String processedLink = _extractJoinLink(fullLink);
if (!processedLink.contains('join/')) {
@@ -309,6 +327,39 @@ class _HomeScreenState extends State<HomeScreen> {
}
});
});
} else if (isChannelLink) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Загрузка информации о канале...'),
behavior: SnackBarBehavior.floating,
margin: EdgeInsets.all(10),
duration: Duration(seconds: 10),
),
);
ApiService.instance.waitUntilOnline().then((_) {
ApiService.instance
.getChatInfoByLink(fullLink)
.then((chatInfo) {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
if (mounted) {
_showChannelSubscribeDialog(chatInfo, fullLink);
}
})
.catchError((error) {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Ошибка: ${error.toString()}'),
backgroundColor: Theme.of(context).colorScheme.error,
behavior: SnackBarBehavior.floating,
margin: const EdgeInsets.all(10),
),
);
}
});
});
}
}
@@ -530,6 +581,227 @@ class _HomeScreenState extends State<HomeScreen> {
);
}
void _showChannelSubscribeDialog(
Map<String, dynamic> chatInfo,
String linkToJoin,
) {
final String title = chatInfo['title'] ?? 'Канал';
final String? iconUrl =
chatInfo['baseIconUrl'] ?? chatInfo['baseUrl'] ?? chatInfo['iconUrl'];
int subscribeState = 0;
String? errorMessage;
showDialog(
context: context,
barrierDismissible: false,
builder: (dialogContext) {
return StatefulBuilder(
builder: (context, setState) {
Widget content;
List<Widget> actions = [];
if (subscribeState == 1) {
content = Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 32),
const CircularProgressIndicator(),
const SizedBox(height: 24),
Text(
'Подписка...',
style: Theme.of(context).textTheme.titleLarge,
textAlign: TextAlign.center,
),
const SizedBox(height: 32),
],
);
actions = [];
} else if (subscribeState == 2) {
content = Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 32),
const Icon(
Icons.check_circle_outline,
color: Colors.green,
size: 60,
),
const SizedBox(height: 24),
Text(
'Вы подписались на канал!',
style: Theme.of(context).textTheme.titleLarge,
textAlign: TextAlign.center,
),
const SizedBox(height: 32),
],
);
actions = [
FilledButton(
child: const Text('Отлично'),
onPressed: () {
Navigator.of(dialogContext).pop();
},
),
];
} else if (subscribeState == 3) {
content = Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 32),
Icon(
Icons.error_outline,
color: Theme.of(context).colorScheme.error,
size: 60,
),
const SizedBox(height: 24),
Text(
'Ошибка',
style: Theme.of(context).textTheme.titleLarge,
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
Text(
errorMessage ?? 'Не удалось подписаться на канал.',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodySmall,
),
const SizedBox(height: 32),
],
);
actions = [
TextButton(
child: const Text('Закрыть'),
onPressed: () {
Navigator.of(dialogContext).pop();
},
),
];
} else {
content = Column(
mainAxisSize: MainAxisSize.min,
children: [
if (iconUrl != null && iconUrl.isNotEmpty)
CircleAvatar(
radius: 60,
backgroundImage: NetworkImage(iconUrl),
onBackgroundImageError: (e, s) {
print("Ошибка загрузки аватара канала: $e");
},
backgroundColor: Colors.grey.shade300,
)
else
CircleAvatar(
radius: 60,
backgroundColor: Colors.grey.shade300,
child: const Icon(
Icons.campaign,
size: 60,
color: Colors.white,
),
),
const SizedBox(height: 24),
Text(
title,
style: Theme.of(context).textTheme.titleLarge,
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
const Text(
'Вы действительно хотите подписаться на этот канал?',
textAlign: TextAlign.center,
),
],
);
actions = [
TextButton(
child: const Text('Отмена'),
onPressed: () {
Navigator.of(dialogContext).pop();
},
),
FilledButton(
child: const Text('Подписаться'),
onPressed: () async {
setState(() {
subscribeState = 1;
});
try {
await ApiService.instance.subscribeToChannel(linkToJoin);
setState(() {
subscribeState = 2;
});
ApiService.instance.clearChatsCache();
await Future.delayed(const Duration(seconds: 2));
if (mounted) {
Navigator.of(dialogContext).pop();
}
} catch (e) {
setState(() {
subscribeState = 3;
errorMessage = e.toString().replaceFirst(
"Exception: ",
"",
);
});
}
},
),
];
}
return AlertDialog(
title: subscribeState == 0
? const Text('Подписаться на канал?')
: null,
content: AnimatedSize(
duration: const Duration(milliseconds: 250),
curve: Curves.easeInOut,
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 250),
transitionBuilder:
(Widget child, Animation<double> animation) {
final slideAnimation =
Tween<Offset>(
begin: const Offset(0, 0.2),
end: Offset.zero,
).animate(
CurvedAnimation(
parent: animation,
curve: Curves.easeOutQuart,
),
);
return FadeTransition(
opacity: animation,
child: SlideTransition(
position: slideAnimation,
child: child,
),
);
},
child: Container(
key: ValueKey<int>(subscribeState),
child: content,
),
),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
actionsAlignment: MainAxisAlignment.center,
actions: actions,
);
},
);
},
);
}
String _extractJoinLink(String inputLink) {
final link = inputLink.trim();