account_user_page.dart 10.3 KB
import 'dart:io';

import 'package:appframe/bloc/setting/account_user_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
import 'package:wechat_camera_picker/wechat_camera_picker.dart';

class AccountUserPage extends StatelessWidget {
  const AccountUserPage({super.key});

  @override
  Widget build(BuildContext context) {
    final Map<String, dynamic>? extraData = GoRouterState.of(context).extra as Map<String, dynamic>?;
    var name = extraData?['name'] ?? '';
    var nickname = extraData?['nickname'] ?? '';
    var avatar = extraData?['avatar'] ?? '';

    return BlocProvider(
      create: (context) => AccountUserCubit(AccountUserState(name: name, nickname: nickname, avatar: avatar)),
      child: BlocConsumer<AccountUserCubit, AccountUserState>(
        builder: (context, state) {
          final accountUserCubit = context.read<AccountUserCubit>();
          return Scaffold(
            backgroundColor: Colors.white,
            appBar: AppBar(
              title: Text('设置用户信息', style: TextStyle(color: Colors.white, fontSize: 18)),
              centerTitle: true,
              backgroundColor: Color(0xFF7691FA),
              iconTheme: IconThemeData(
                color: Colors.white,
              ),
            ),
            body: SingleChildScrollView(
              child: Padding(
                padding: EdgeInsets.all(20),
                child: Column(
                  children: [
                    SizedBox(height: 40),
                    GestureDetector(
                      onTap: () => _pickImage(context, accountUserCubit),
                      child: Stack(
                        children: [
                          CircleAvatar(
                            radius: 50,
                            backgroundColor: Color(0xFFF7F9FF),
                            backgroundImage: state.avatar.isNotEmpty
                                ? (state.avatar.startsWith('http')
                                    ? NetworkImage(state.avatar)
                                    : FileImage(File(state.avatar))) as ImageProvider
                                : null,
                            child: state.avatar.isEmpty
                                ? Icon(
                                    Icons.person,
                                    size: 50,
                                    color: Color(0xFFCCCCCC),
                                  )
                                : null,
                          ),
                          Positioned(
                            right: 0,
                            bottom: 0,
                            child: Container(
                              width: 30,
                              height: 30,
                              decoration: BoxDecoration(
                                color: Color(0xFF7691FA),
                                shape: BoxShape.circle,
                              ),
                              child: Icon(
                                Icons.camera_alt,
                                color: Colors.white,
                                size: 16,
                              ),
                            ),
                          ),
                        ],
                      ),
                    ),
                    SizedBox(height: 20),
                    Text(
                      '点击更换头像',
                      style: TextStyle(
                        fontSize: 14,
                        color: Color(0xFF999999),
                      ),
                    ),
                    SizedBox(height: 40),
                    _buildInfoItem(
                      context,
                      icon: Icons.person_outline,
                      label: '姓名',
                      controller: accountUserCubit.nameController,
                      hintText: '请输入姓名',
                    ),
                    SizedBox(height: 20),
                    _buildInfoItem(
                      context,
                      icon: Icons.badge_outlined,
                      label: '昵称',
                      controller: accountUserCubit.nickNameController,
                      hintText: '请输入昵称',
                    ),
                    SizedBox(height: 60),
                    SizedBox(
                      width: double.infinity,
                      height: 47,
                      child: ElevatedButton(
                        onPressed: state.isLoading
                            ? null
                            : () {
                                accountUserCubit.save();
                              },
                        style: ElevatedButton.styleFrom(
                          backgroundColor: Color(0xFF7691FA),
                          foregroundColor: Colors.white,
                          textStyle: TextStyle(fontSize: 19),
                          shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(23.5),
                          ),
                          disabledBackgroundColor: Color(0xFFCCCCCC),
                        ),
                        child: state.isLoading
                            ? SizedBox(
                                width: 20,
                                height: 20,
                                child: CircularProgressIndicator(
                                  strokeWidth: 2,
                                  valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
                                ),
                              )
                            : Text(
                                '保存',
                                style: TextStyle(
                                  fontSize: 19,
                                  fontWeight: FontWeight.w400,
                                  color: Color(0xFFFFFFFF),
                                ),
                                strutStyle: StrutStyle(height: 22 / 19),
                              ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          );
        },
        listener: (context, state) {
          if (state.showSnackBar) {
            _showTip(context, state.snackBarMsg);
          }
        },
      ),
    );
  }

  Widget _buildInfoItem(
    BuildContext context, {
    required IconData icon,
    required String label,
    required TextEditingController controller,
    required String hintText,
  }) {
    return Container(
      padding: EdgeInsets.symmetric(horizontal: 20, vertical: 15),
      decoration: BoxDecoration(
        color: Color(0xFFF7F9FF),
        borderRadius: BorderRadius.circular(10),
      ),
      child: Row(
        children: [
          Icon(
            icon,
            color: Color(0xFF7691FA),
            size: 24,
          ),
          SizedBox(width: 15),
          Text(
            label,
            style: TextStyle(
              fontSize: 16,
              color: Color(0xFF333333),
              fontWeight: FontWeight.w500,
            ),
          ),
          SizedBox(width: 20),
          Expanded(
            child: TextField(
              controller: controller,
              decoration: InputDecoration(
                hintText: hintText,
                hintStyle: TextStyle(
                  fontSize: 16,
                  color: Color(0xFFCCCCCC),
                ),
                border: InputBorder.none,
                isDense: true,
                contentPadding: EdgeInsets.zero,
              ),
              style: TextStyle(
                fontSize: 16,
                color: Color(0xFF000000),
              ),
              textAlign: TextAlign.center,
            ),
          ),
        ],
      ),
    );
  }

  Future<void> _pickImage(BuildContext context, AccountUserCubit cubit) async {
    showModalBottomSheet(
      context: context,
      builder: (BuildContext context) {
        return SafeArea(
          child: Wrap(
            children: [
              ListTile(
                leading: Icon(Icons.photo_camera),
                title: Text('拍照'),
                onTap: () async {
                  Navigator.pop(context);

                  AssetEntity? asset = await CameraPicker.pickFromCamera(
                    context,
                    pickerConfig: const CameraPickerConfig(),
                  );
                  if (asset != null) {
                    cubit.updateAvatar((await asset.file)!.path);
                  }
                },
              ),
              ListTile(
                leading: Icon(Icons.photo_library),
                title: Text('从相册选择'),
                onTap: () async {
                  Navigator.pop(context);

                  List<AssetEntity>? result = await AssetPicker.pickAssets(
                    context,
                    pickerConfig: AssetPickerConfig(
                      maxAssets: 1,
                      requestType: RequestType.image,
                      dragToSelect: false,
                    ),
                  );

                  if (result != null) {
                    cubit.updateAvatar((await result.first.file)!.path);
                  }
                },
              ),
              ListTile(
                leading: Icon(Icons.cancel),
                title: Text('取消'),
                onTap: () {
                  Navigator.pop(context);
                },
              ),
            ],
          ),
        );
      },
    );
  }

  void _showTip(BuildContext context, String tip) {
    OverlayEntry overlayEntry = OverlayEntry(
      builder: (context) => Positioned(
        top: 200,
        left: 20,
        right: 20,
        child: Material(
          color: Colors.transparent,
          child: Container(
            padding: EdgeInsets.all(16),
            decoration: BoxDecoration(
              color: Colors.black54,
              borderRadius: BorderRadius.circular(8),
            ),
            child: Text(
              tip,
              style: TextStyle(color: Colors.white),
              textAlign: TextAlign.center,
            ),
          ),
        ),
      ),
    );

    Overlay.of(context).insert(overlayEntry);
    Future.delayed(Duration(seconds: 2), () {
      overlayEntry.remove();
    });
  }
}