link_cubit.dart 3.83 KB
import 'dart:convert';

import 'package:appframe/config/routes.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:webview_flutter/webview_flutter.dart';

class LinkState extends Equatable {
  final bool loaded;
  final String url;
  final String title;
  final int screenType; // 1: 竖屏, 2: 横屏

  const LinkState({
    this.loaded = false,
    this.url = '',
    this.title = '',
    this.screenType = 1,
  });

  LinkState copyWith({
    bool? loaded,
    String? url,
    String? title,
    int? screenType,
  }) {
    return LinkState(
      loaded: loaded ?? this.loaded,
      url: url ?? this.url,
      title: title ?? this.title,
      screenType: screenType ?? this.screenType,
    );
  }

  @override
  List<Object?> get props => [
        loaded,
        url,
        title,
        screenType,
      ];
}

class LinkCubit extends Cubit<LinkState> {
  late final WebViewController _controller;
  String? msg;

  WebViewController get controller => _controller;

  LinkCubit(super.initialState) {
    if (state.screenType != 1) {
      _setOrientation(2);
    }

    _controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..setNavigationDelegate(
        NavigationDelegate(
          onUrlChange: (UrlChange url) {},
          onPageStarted: (String url) {},
          onPageFinished: (String url) async {
            _controller.runJavaScript(
              'document.querySelector("meta[name=viewport]").setAttribute("content", "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no")',
            );

            // 如果 state.title 为空,则读取网页的 title
            if (state.title.isEmpty) {
              final pageTitle = await _controller.runJavaScriptReturningResult('document.title') as String?;
              // 移除可能存在的引号
              final cleanTitle = pageTitle?.replaceAll('"', '');
              emit(state.copyWith(title: cleanTitle ?? ''));
            }

            _finishLoading();
          },
        ),
      )
      ..addJavaScriptChannel("xeJsBridge", onMessageReceived: (JavaScriptMessage message) {})
      ..loadRequest(Uri.parse(state.url));
  }

  void _onMessageReceived(JavaScriptMessage message) async {
    // try {
    //   _dispatcher.dispatch(message.message, (response) {
    //     _sendResponse(response);
    //   }, webCubit: this);
    // } catch (e) {
    //   debugPrint('消息解析错误: $e');
    // }
  }

  // 向H5发送响应
  void _sendResponse(Map<String, dynamic> response) {
    String jsonString = jsonEncode(response);
    String escapedJson = jsonString.replaceAll('"', '\\"');
    final String script = 'xeJsBridgeCallback("$escapedJson");';
    _controller.runJavaScript(script);
  }

  void _finishLoading() {
    emit(state.copyWith(loaded: true));
  }

  // 设置屏幕方向
  void _setOrientation(int screenType) {
    if (screenType == 2) {
      // 横屏模式
      SystemChrome.setPreferredOrientations([
        DeviceOrientation.landscapeLeft,
        DeviceOrientation.landscapeRight,
      ]);
      // 隐藏状态栏
      SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
    } else {
      // 竖屏模式(默认)
      SystemChrome.setPreferredOrientations([
        DeviceOrientation.portraitUp,
        DeviceOrientation.portraitDown,
      ]);
      // 显示状态栏
      SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
    }
  }

  Future<void> handleBack() async {
    if (await _controller.canGoBack()) {
      _controller.goBack();
    } else {
      router.pop(msg);
    }
  }

  @override
  Future<void> close() {
    // 恢复为竖屏模式
    if (state.screenType != 1) {
      _setOrientation(1);
    }

    return super.close();
  }
}