Files
doyin/lib/app/modules/chat/contactModule/contactViews/ContactPage/contactPage.dart
2025-07-09 18:32:34 +08:00

179 lines
6.7 KiB
Dart

import 'package:caller/app/models/contactModels/contactModels.dart';
import 'package:caller/app/modules/chat/contactModule/contactViews/ContactPage/contactInfo.dart';
import 'package:caller/app/modules/chat/contactModule/controllers/contactController.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:cached_network_image/cached_network_image.dart';
class ContactsPage extends StatelessWidget {
final ScrollController sC = ScrollController();
final Map<String, GlobalKey> letterKeys = {};
@override
Widget build(BuildContext context) {
// Access ContactController
final contactController = Get.find<ContactController>();
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
body: Stack(
children: [
Obx(() {
final totalCount = contactController.functionButtons.length + contactController.contacts.length;
return ListView.builder(
controller: sC,
itemCount: totalCount,
itemBuilder: (context, index) {
if (index < contactController.functionButtons.length) {
// Show function buttons first
final item = contactController.functionButtons[index];
return _buildFunctionButton(item,context);
} else {
// Show contacts after function buttons
final contactIndex = index - contactController.functionButtons.length;
final contact = contactController.contacts[contactIndex];
final showHeader = contactIndex == 0 ||
contact.nameIndex != contactController.contacts[contactIndex - 1].nameIndex;
final letterKey = showHeader
? letterKeys.putIfAbsent(
contact.nameIndex!,
() => GlobalKey(),
)
: null;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (showHeader)
Container(
key: letterKey,
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 6,
),
child: Text(
contact.nameIndex!,
style: TextStyle(
fontSize: 14,
color: Colors.grey[700],
fontWeight: FontWeight.bold,
),
),
),
Container(
color: Theme.of(context).cardColor,
child: ListTile(
leading: CircleAvatar(
radius: 24,
backgroundImage: CachedNetworkImageProvider(contact.avatarUrl),
),
title: Text(
contact.name,
style: TextStyle(fontSize: 16),
),
subtitle: contact.statusMessage != null
? Text(contact.statusMessage!)
: null,
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 2),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (_)=>ContactInfoPage(contact: contact,)));
},
),
),
Divider(thickness: 0.3,
height: 0.1, color: Theme.of(context).dividerColor),
],
);
}
},
);
}),
Positioned(
right: 10,
top: 100,
bottom: 100,
width: 24,
child: _buildIndexBar(context, contactController),
),
Obx(() => _buildCurrentLetterIndicator(contactController)),
],
),
);
}
// Build function button UI
Widget _buildFunctionButton(ContactItem item,BuildContext context) {
return Container(
color: Theme.of(context).cardColor,
child: ListTile(
leading: Image.asset(item.avatar, width: 36, height: 36),
title: Text(item.title.tr),
onTap: () {},
),
);
}
// Index bar on the right side
Widget _buildIndexBar(BuildContext context, ContactController contactController) {
return GestureDetector(
onVerticalDragUpdate: (details) =>
_handleDrag(details.localPosition.dy, context, contactController),
onVerticalDragStart: (details) =>
_handleDrag(details.localPosition.dy, context, contactController),
onTapDown: (details) =>
_handleDrag(details.localPosition.dy, context, contactController),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: INDEX_BAR_WORDS
.map(
(e) => Text(e, style: TextStyle(fontSize: 12, color: Colors.grey)),
)
.toList(),
),
);
}
// Handle drag events when the user drags on the index bar
void _handleDrag(
double localDy,
BuildContext context,
ContactController contactController,
) {
final box = context.findRenderObject() as RenderBox;
final tileHeight = box.size.height / INDEX_BAR_WORDS.length;
final index = (localDy ~/ tileHeight).clamp(0, INDEX_BAR_WORDS.length - 1);
final letter = INDEX_BAR_WORDS[index];
contactController.jumpToIndex(letter, sC, letterKeys);
}
// Display current letter indicator when dragging
Widget _buildCurrentLetterIndicator(ContactController contactController) {
if (contactController.currentLetter.value.isEmpty) return SizedBox.shrink();
return Center(
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Colors.black54,
borderRadius: BorderRadius.circular(40),
),
alignment: Alignment.center,
child: Text(
contactController.currentLetter.value,
style: TextStyle(
fontSize: 32,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
);
}
}
// === MOCK INDEX BAR WORDS ===
const List<String> INDEX_BAR_WORDS = [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
];