Compare commits
26 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
d008eebe64 | |
|
|
bc3b05403d | |
|
|
a019645104 | |
|
|
f5ecc0eb51 | |
|
|
44180f9924 | |
|
|
976b76adae | |
|
|
bd635a53b6 | |
|
|
01b4adeac7 | |
|
|
9161c33741 | |
|
|
87bea363b6 | |
|
|
cf8f710a38 | |
|
|
a6c8b475f4 | |
|
|
68288fdc00 | |
|
|
c98a1db1d3 | |
|
|
363fd0b77c | |
|
|
1938e02207 | |
|
|
045c730899 | |
|
|
51442d27f3 | |
|
|
0b5f41ee12 | |
|
|
54594ade8c | |
|
|
0ec8987acc | |
|
|
307ba4f020 | |
|
|
8f08223a18 | |
|
|
8df34b0fa7 | |
|
|
bb41882757 | |
|
|
c5b55d8660 |
|
|
@ -5,9 +5,11 @@
|
|||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.build/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
.swiftpm/
|
||||
migrate_working_dir/
|
||||
.fvm/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,28 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- 摄像头 -->
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<!-- 麦克风 -->
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<!-- 网络 -->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<!-- 安装 -->
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<!-- 写权限 -->
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<!-- 读权限 -->
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<!-- 屏幕常亮 -->
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<!-- 高android版本读写权限 -->
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
||||
|
||||
<application
|
||||
android:label="智汇享"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:enableOnBackInvokedCallback="true">
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:usesCleartextTraffic="true">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
|
|
@ -36,47 +50,19 @@
|
|||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
<!-- 访问电话状态 -->
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_PHONE_STATE"/>
|
||||
<!-- 允许全部网络访问 -->
|
||||
<uses-permission
|
||||
android:name="android.permission.INTERNET"/>
|
||||
<!-- 获取网络信息状态 -->
|
||||
<uses-permission
|
||||
android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<!-- 获取当前WiFi接入的状态以及WLAN热点的信息 -->
|
||||
<uses-permission
|
||||
android:name="android.permission.ACCESS_WIFI_STATE"/>
|
||||
<!-- 获取当前设备存储权限 -->
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.ACTION_MANAGE_UNKNOWN_APP_SOURCES"/>
|
||||
<!-- 这个权限用于app安装 -->
|
||||
<uses-permission
|
||||
android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
|
||||
<!-- 屏幕常亮权限 -->
|
||||
<uses-permission
|
||||
android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.CAMERA"/>
|
||||
<!-- Permissions options for the `access notification policy` group -->
|
||||
<uses-permission
|
||||
android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/>
|
||||
<!-- Permissions options for the `notification` group -->
|
||||
<uses-permission
|
||||
android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
<!-- Required to query activities that can process text, see:
|
||||
https://developer.android.com/training/package-visibility and
|
||||
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
||||
|
||||
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_path" />
|
||||
</provider>
|
||||
<!-- ${applicationId}会被替换为你的应用ID -->
|
||||
<!-- android:resource="@xml/file_paths"指定了存放共享文件路径的资源文件。 -->
|
||||
</application>
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="?android:colorBackground" />
|
||||
<!--<item android:drawable="?android:colorBackground"/ >-->
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:gravity="fill"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</item>
|
||||
</layer-list>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/white" />
|
||||
<!--<item android:drawable="@android:color/white"/ >-->
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:gravity="fill"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</item>
|
||||
</layer-list>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 442 B After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 721 B After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 976 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 9.7 KiB |
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<paths>
|
||||
<root-path name="root" path="" />
|
||||
<files-path name="files" path="" />
|
||||
<cache-path name="cache" path="" />
|
||||
<external-path name="external" path="" />
|
||||
<external-files-path name="external_files" path="" />
|
||||
<external-cache-path name="external_cache" path="" />
|
||||
</paths>
|
||||
</resources>
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
android.suppressUnsupportedCompileSdk=34
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
|
@ -7,6 +7,7 @@ import UIKit
|
|||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
Thread.sleep(forTimeInterval: 3) // 加入此行代码,便可延迟2秒关闭启动页
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,115 +2,153 @@
|
|||
"images": [
|
||||
{
|
||||
"size": "20x20",
|
||||
"idiom": "universal",
|
||||
"idiom": "iphone",
|
||||
"filename": "icon-20@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "20x20",
|
||||
"idiom": "universal",
|
||||
"idiom": "iphone",
|
||||
"filename": "icon-20@3x.png",
|
||||
"scale": "3x",
|
||||
"platform": "ios"
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "universal",
|
||||
"idiom": "iphone",
|
||||
"filename": "icon-29.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "iphone",
|
||||
"filename": "icon-29@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "universal",
|
||||
"idiom": "iphone",
|
||||
"filename": "icon-29@3x.png",
|
||||
"scale": "3x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "38x38",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-38@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
},
|
||||
{
|
||||
"size": "38x38",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-38@3x.png",
|
||||
"scale": "3x",
|
||||
"platform": "ios"
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "universal",
|
||||
"idiom": "iphone",
|
||||
"filename": "icon-40@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "universal",
|
||||
"idiom": "iphone",
|
||||
"filename": "icon-40@3x.png",
|
||||
"scale": "3x",
|
||||
"platform": "ios"
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"size": "57x57",
|
||||
"idiom": "iphone",
|
||||
"filename": "icon-57.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "57x57",
|
||||
"idiom": "iphone",
|
||||
"filename": "icon-57@2x.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "60x60",
|
||||
"idiom": "universal",
|
||||
"idiom": "iphone",
|
||||
"filename": "icon-60@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "60x60",
|
||||
"idiom": "universal",
|
||||
"idiom": "iphone",
|
||||
"filename": "icon-60@3x.png",
|
||||
"scale": "3x",
|
||||
"platform": "ios"
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"size": "64x64",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-64@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
"size": "20x20",
|
||||
"idiom": "ipad",
|
||||
"filename": "icon-20-ipad.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "64x64",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-64@3x.png",
|
||||
"scale": "3x",
|
||||
"platform": "ios"
|
||||
"size": "20x20",
|
||||
"idiom": "ipad",
|
||||
"filename": "icon-20@2x-ipad.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "68x68",
|
||||
"idiom": "universal",
|
||||
"filename": "icon-68@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
"size": "29x29",
|
||||
"idiom": "ipad",
|
||||
"filename": "icon-29-ipad.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "ipad",
|
||||
"filename": "icon-29@2x-ipad.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "ipad",
|
||||
"filename": "icon-40.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "ipad",
|
||||
"filename": "icon-40@2x.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "50x50",
|
||||
"idiom": "ipad",
|
||||
"filename": "icon-50.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "50x50",
|
||||
"idiom": "ipad",
|
||||
"filename": "icon-50@2x.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "72x72",
|
||||
"idiom": "ipad",
|
||||
"filename": "icon-72.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "72x72",
|
||||
"idiom": "ipad",
|
||||
"filename": "icon-72@2x.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "76x76",
|
||||
"idiom": "universal",
|
||||
"idiom": "ipad",
|
||||
"filename": "icon-76.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "76x76",
|
||||
"idiom": "ipad",
|
||||
"filename": "icon-76@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "83.5x83.5",
|
||||
"idiom": "universal",
|
||||
"idiom": "ipad",
|
||||
"filename": "icon-83.5@2x.png",
|
||||
"scale": "2x",
|
||||
"platform": "ios"
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "1024x1024",
|
||||
"idiom": "universal",
|
||||
"idiom": "ios-marketing",
|
||||
"filename": "icon-1024.png",
|
||||
"scale": "1x",
|
||||
"platform": "ios"
|
||||
"scale": "1x"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 161 KiB |
|
After Width: | Height: | Size: 920 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 68 B |
|
Before Width: | Height: | Size: 68 B |
|
Before Width: | Height: | Size: 68 B |
|
|
@ -1,8 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
|
|
@ -14,9 +16,11 @@
|
|||
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
|
||||
<imageView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" misplaced="YES" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
|
||||
<rect key="frame" x="2" y="93" width="375" height="759"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
|
@ -28,10 +32,10 @@
|
|||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
<point key="canvasLocation" x="121.37404580152672" y="185.91549295774649"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="LaunchImage" width="168" height="185"/>
|
||||
<image name="LaunchImage" width="375" height="667"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
|
|
@ -18,12 +18,21 @@
|
|||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="0Yj-sA-xJG">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="9" y="-76"/>
|
||||
<point key="canvasLocation" x="8.3969465648854964" y="-76.056338028169023"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="LaunchImage" width="375" height="667"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string></string>
|
||||
<string>Main.storyboard</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiresFullScreen</key>
|
||||
|
|
|
|||
|
|
@ -103,4 +103,10 @@ abstract class RetrofitClient {
|
|||
@Query("enableCamera") bool enableCamera,
|
||||
@Query("uid") String uid,
|
||||
);
|
||||
|
||||
/// 刷新登录Token
|
||||
@POST("/auth/refresh")
|
||||
Future<BaseStructureResult<UserInfoEntity>> refreshToken(
|
||||
@Query("refreshToken") String refreshToken,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ class RequestConfig {
|
|||
// static const _devBaseUrl = "https://zyapitest.23544.com:16440"; // 开发
|
||||
static const _devBaseUrl = "http://192.168.2.9:5192"; // 开发
|
||||
// static const _proBaseUrl = "http://192.168.2.119:1091"; // 生产
|
||||
static const _proBaseUrl = "https://zyapi.23544.com/ipadapi"; // 生产
|
||||
static const _proBaseUrl = "http://192.168.2.9:5192"; // 生产
|
||||
static const imgUrl = 'https://dpc-job-oss.23544.com/';
|
||||
|
||||
static RequestConfig? _instance;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'app_updata_info_entity.g.dart';
|
||||
|
||||
@JsonSerializable(checked: true)
|
||||
class AppUpdataInfoEntity extends Object{
|
||||
|
||||
@JsonKey(name: 'versionCode')
|
||||
int versionCode;
|
||||
|
||||
@JsonKey(name: 'versionName')
|
||||
String versionName;
|
||||
|
||||
@JsonKey(name: 'updateType')
|
||||
int updateType;
|
||||
|
||||
@JsonKey(name: 'versionDescribe')
|
||||
String versionDescribe;
|
||||
|
||||
@JsonKey(name: 'androidurl')
|
||||
String androidurl;
|
||||
|
||||
@JsonKey(name: 'appStoreUrl')
|
||||
String appStoreUrl;
|
||||
|
||||
@JsonKey(name: 'apkSavePath')
|
||||
String apkSavePath;
|
||||
|
||||
AppUpdataInfoEntity(this.versionCode,this.versionName,this.updateType,this.versionDescribe,this.androidurl,this.appStoreUrl,this.apkSavePath);
|
||||
|
||||
factory AppUpdataInfoEntity.fromJson(Map<String, dynamic> srcJson) => _$AppUpdataInfoEntityFromJson(srcJson);
|
||||
|
||||
Map<String, dynamic> toJson() => _$AppUpdataInfoEntityToJson(this);
|
||||
}
|
||||
|
|
@ -6,6 +6,8 @@ import 'package:dio/dio.dart';
|
|||
import 'package:wgshare/common/api/retrofit_client.dart';
|
||||
import 'package:wgshare/common/config/request_config.dart';
|
||||
import 'package:wgshare/common/store/user_store.dart';
|
||||
import 'package:wgshare/utils/anti_shake_throttling.dart';
|
||||
import 'package:wgshare/utils/routeUtil.dart';
|
||||
import 'package:wgshare/utils/storage.dart';
|
||||
import 'package:wgshare/utils/toast_utils.dart';
|
||||
import 'package:wgshare/routes/app_routes.dart';
|
||||
|
|
@ -111,9 +113,9 @@ class ResponseHandle extends Interceptor {
|
|||
((data['code'] != null && (data['code'] == 401 || data['code'] == '401')) ||
|
||||
(data['Code'] != null && (data['Code'] == 401 || data['Code'] == '401')));
|
||||
|
||||
if (statusCode == 401 || flag) {
|
||||
Future.delayed(const Duration(seconds: 2), () {
|
||||
StorageService.to.erase();
|
||||
if ((statusCode == 401 || flag) && RouteUtil.getRoute() != Routes.loginPage) {
|
||||
easyThrottle("toLogin",(){
|
||||
UserStore.to.erase();
|
||||
getx.Get.offAllNamed(Routes.loginPage);
|
||||
});
|
||||
}
|
||||
|
|
@ -163,12 +165,12 @@ class TheError extends Interceptor {
|
|||
switch (statusCode) {
|
||||
case 401:
|
||||
message = '用户登录失效,请重新登录';
|
||||
|
||||
Future.delayed(const Duration(seconds: 2), () {
|
||||
// UserStore.to.erase();
|
||||
StorageService.to.erase();
|
||||
if(RouteUtil.getRoute() != Routes.loginPage){
|
||||
easyThrottle("toLogin",(){
|
||||
UserStore.to.erase();
|
||||
getx.Get.offAllNamed(Routes.loginPage);
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 404:
|
||||
message = '无效地址';
|
||||
|
|
|
|||
|
|
@ -2,10 +2,14 @@
|
|||
|
||||
enum AppStorageKey {
|
||||
token(value: 'TOKEN', label: "登录用户的token"),
|
||||
refreshToken(value: 'REFRESHTOKEN', label: "刷新用的token"),
|
||||
userInfo(value: 'USERINFO', label: "登录用户的基本信息"),
|
||||
account(value: 'ACCOUNT', label: "用户名"),
|
||||
pwd(value: 'PWD', label: "密码"),
|
||||
loginType(value: 'LOGINTYPE', label: "登录类型");
|
||||
loginType(value: 'LOGINTYPE', label: "登录类型"),
|
||||
appUpDataInfo(value: 'APPUPDATAINFO', label: "app更新信息"),
|
||||
isRefuseHomeCheckPermission(value: 'ISREFUSEHOMECHECKPERMISSION', label: "是否拒绝会议列表页请求文件访问权限"),
|
||||
skipUpVersion(value: 'SKIPUPVERSION', label: "跳过此版本更新的版本号"),;
|
||||
|
||||
final String label;
|
||||
final String value;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
import 'package:get/get.dart';
|
||||
import 'package:wgshare/common/mixins/request_tool_mixin.dart';
|
||||
import 'package:wgshare/common/store/app_storage_key.dart';
|
||||
import 'package:wgshare/utils/storage.dart';
|
||||
|
||||
import '../models/app_updata_info_entity.dart';
|
||||
|
||||
class BusinessStore extends GetxController with RequestToolMixin {
|
||||
static BusinessStore get to => Get.find();
|
||||
|
||||
/// app版本更新信息
|
||||
Rx<AppUpdataInfoEntity?> appUpdataInfoEntity = Rx(null);
|
||||
|
||||
/// 是否拒绝会议列表页请求文件访问权限
|
||||
bool? isRefuseHomeCheckPermission = false;
|
||||
|
||||
/// 跳过此版本更新的版本号
|
||||
int? skipUpVersion = 0;
|
||||
|
||||
BusinessStore init() {
|
||||
isRefuseHomeCheckPermission = StorageService.to.read(AppStorageKey.isRefuseHomeCheckPermission.value);
|
||||
skipUpVersion = StorageService.to.read(AppStorageKey.skipUpVersion.value);
|
||||
try {
|
||||
var appUpdataInfo = StorageService.to.read(AppStorageKey.appUpDataInfo.value);
|
||||
if (appUpdataInfo != null) {
|
||||
appUpdataInfoEntity.value = AppUpdataInfoEntity.fromJson(appUpdataInfo);
|
||||
}
|
||||
} catch (err) {
|
||||
StorageService.to.remove(AppStorageKey.userInfo.value);
|
||||
appUpdataInfoEntity.value = null;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// 缓存app版本更新信息
|
||||
void setAppUpdataInfo(AppUpdataInfoEntity info) {
|
||||
appUpdataInfoEntity.value = info;
|
||||
StorageService.to.write(AppStorageKey.appUpDataInfo.value, info);
|
||||
}
|
||||
|
||||
/// 缓存是否拒绝会议列表页请求文件访问权限状态
|
||||
void setIsRefuseHomeCheckPermission(bool type) {
|
||||
isRefuseHomeCheckPermission = type;
|
||||
StorageService.to.write(AppStorageKey.isRefuseHomeCheckPermission.value, type);
|
||||
}
|
||||
|
||||
/// 跳过此版本更新的版本号
|
||||
void setSkipUpVersion(int code) {
|
||||
skipUpVersion = code;
|
||||
StorageService.to.write(AppStorageKey.skipUpVersion.value, code);
|
||||
}
|
||||
|
||||
/// 清空缓存app版本更新信息
|
||||
void erase() {
|
||||
appUpdataInfoEntity.value = null;
|
||||
StorageService.to.write(AppStorageKey.appUpDataInfo.value, null);
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,9 @@ class UserStore extends GetxController with RequestToolMixin {
|
|||
/// 是否登录
|
||||
String? token;
|
||||
|
||||
/// 刷新用的token
|
||||
String? refreshToken;
|
||||
|
||||
/// 登录类型
|
||||
String? loginType;
|
||||
|
||||
|
|
@ -23,6 +26,7 @@ class UserStore extends GetxController with RequestToolMixin {
|
|||
UserStore init() {
|
||||
loginType = StorageService.to.read(AppStorageKey.loginType.value);
|
||||
token = StorageService.to.read(AppStorageKey.token.value);
|
||||
refreshToken = StorageService.to.read(AppStorageKey.refreshToken.value);
|
||||
try {
|
||||
var userDetail = StorageService.to.read(AppStorageKey.userInfo.value);
|
||||
if (userDetail != null) {
|
||||
|
|
@ -45,6 +49,12 @@ class UserStore extends GetxController with RequestToolMixin {
|
|||
StorageService.to.write(AppStorageKey.token.value, token);
|
||||
}
|
||||
|
||||
/// 保存refreshToken
|
||||
void setRefreshToken(String refreshToken) {
|
||||
this.refreshToken = refreshToken;
|
||||
StorageService.to.write(AppStorageKey.refreshToken.value, refreshToken);
|
||||
}
|
||||
|
||||
/// 保存登录类型
|
||||
void setLoginType(String loginType) {
|
||||
this.loginType = loginType;
|
||||
|
|
@ -61,9 +71,14 @@ class UserStore extends GetxController with RequestToolMixin {
|
|||
void erase() {
|
||||
userInfoEntity.value = null;
|
||||
token = null;
|
||||
refreshToken = null;
|
||||
loginType = null;
|
||||
|
||||
StorageService.to.erase();
|
||||
StorageService.to.write(AppStorageKey.userInfo.value, null);
|
||||
StorageService.to.write(AppStorageKey.token.value, null);
|
||||
StorageService.to.write(AppStorageKey.refreshToken.value, null);
|
||||
StorageService.to.write(AppStorageKey.loginType.value, null);
|
||||
// StorageService.to.erase();
|
||||
}
|
||||
|
||||
// 用户信息更新
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:al_downloader/al_downloader.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
|
|
@ -12,6 +15,7 @@ import 'package:wgshare/utils/utils.dart';
|
|||
|
||||
import 'common/config/app_config.dart';
|
||||
import 'common/config/colorUtils.dart';
|
||||
import 'common/store/business_store.dart';
|
||||
import 'routes/app_pages.dart';
|
||||
import 'routes/app_routes.dart';
|
||||
|
||||
|
|
@ -26,6 +30,12 @@ void main() async {
|
|||
|
||||
/// 初始化UserStore
|
||||
Get.put<UserStore>(UserStore().init());
|
||||
Get.put<BusinessStore>(BusinessStore().init());
|
||||
|
||||
/// 初始化后台下载
|
||||
if(Platform.isAndroid){
|
||||
ALDownloader.initialize();
|
||||
}
|
||||
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
import 'package:al_downloader/al_downloader.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:signalr_core/signalr_core.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:wgshare/common/models/common/base_structure_result.dart';
|
||||
import 'package:wgshare/common/mixins/request_tool_mixin.dart';
|
||||
import 'package:wgshare/common/store/business_store.dart';
|
||||
import 'package:wgshare/common/store/user_store.dart';
|
||||
import 'package:wgshare/utils/storage.dart';
|
||||
|
||||
import '../../common/models/meeting_room_item.dart';
|
||||
import '../../routes/app_routes.dart';
|
||||
import '../../utils/permission/PermissionService.dart';
|
||||
import '../../utils/toast_utils.dart';
|
||||
import '../../view/public_dialog.dart';
|
||||
import '../../view/upgrade/loadJson/hide_load_network_json.dart';
|
||||
import 'home_state.dart';
|
||||
|
||||
class HomeLogic extends GetxController with RequestToolMixin {
|
||||
|
|
@ -16,6 +24,37 @@ class HomeLogic extends GetxController with RequestToolMixin {
|
|||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
/// 检查更新(后台)
|
||||
HideCheckVersion hideCheckVersion = HideCheckVersion();
|
||||
hideCheckVersion.doHttpHideCheckVersion();
|
||||
/// 权限
|
||||
/*PermissionService.checkPermission(permissionList: [Permission.manageExternalStorage]).then((value){
|
||||
if(value == true){
|
||||
hideCheckVersion.doHttpHideCheckVersion();
|
||||
}else{
|
||||
if(null == BusinessStore.to.isRefuseHomeCheckPermission || BusinessStore.to.isRefuseHomeCheckPermission == false){
|
||||
publicDialog(Get.context!,
|
||||
hideCancelBtn: true,
|
||||
title: '请求权限说明',
|
||||
describe:
|
||||
'APP需要获取您的文件访问权限,用以确保新版本下载后可以正常安装。',
|
||||
leftBtnStr: '拒绝',
|
||||
rightBtnStr: '同意',
|
||||
leftBtnCallback: () {
|
||||
BusinessStore.to.setIsRefuseHomeCheckPermission(true);
|
||||
}, rightBtnCallback: () {
|
||||
PermissionService.requestStoragePermissions().then((value){
|
||||
if(value == true){
|
||||
hideCheckVersion.doHttpHideCheckVersion();
|
||||
}
|
||||
});
|
||||
});
|
||||
}else{
|
||||
hideCheckVersion.doHttpHideCheckVersion();
|
||||
}
|
||||
}
|
||||
});*/
|
||||
|
||||
doHttpGetMeetingRoomList(state.pageIndex.value, state.pageSize.value);
|
||||
}
|
||||
|
||||
|
|
@ -28,7 +67,8 @@ class HomeLogic extends GetxController with RequestToolMixin {
|
|||
/// 获取会议列表
|
||||
Future<void> doHttpGetMeetingRoomList(int pageIndex, int pageSize) async {
|
||||
debugPrint("wgs输出===:token:${UserStore.to.token}");
|
||||
BaseStructureResult<MeetingRoomItem> res = await getClient().getMeetingRoomList(pageIndex,pageSize);
|
||||
BaseStructureResult<MeetingRoomItem> res = await getClient()
|
||||
.getMeetingRoomList(pageIndex, pageSize);
|
||||
if (null != res.data) {
|
||||
if (state.pageIndex == 1) {
|
||||
state.meetingRooms.value = res.data!.items;
|
||||
|
|
@ -63,7 +103,8 @@ class HomeLogic extends GetxController with RequestToolMixin {
|
|||
DateTime now = DateTime.now();
|
||||
// 物理键,两次间隔大于4秒, 退出请求无效
|
||||
if (state.currentBackPressTime == null ||
|
||||
now.difference(state.currentBackPressTime!) > const Duration(seconds: 4)) {
|
||||
now.difference(state.currentBackPressTime!) >
|
||||
const Duration(seconds: 4)) {
|
||||
state.currentBackPressTime = now;
|
||||
ToastUtils.showInfo("再按一次退出");
|
||||
return false;
|
||||
|
|
@ -73,5 +114,45 @@ class HomeLogic extends GetxController with RequestToolMixin {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// 进入会议室
|
||||
void gotoMeetingRoom(BuildContext context, int index) {
|
||||
PermissionService.checkPermission(
|
||||
permissionList: [Permission.microphone, Permission.camera]).then((
|
||||
value) {
|
||||
if (value == true) {
|
||||
Get.back();
|
||||
Get.toNamed(Routes.meetingMainPage,
|
||||
arguments: {
|
||||
"roomNumber": state.meetingRooms.value[index].roomNum
|
||||
});
|
||||
} else {
|
||||
publicDialog(
|
||||
context,
|
||||
hideCancelBtn: true,
|
||||
title: '请求权限说明',
|
||||
describe: '进入会议室需要获取您的麦克风以及摄像头权限,用以确保能够正常参会发言。',
|
||||
leftBtnStr: '拒绝',
|
||||
rightBtnStr: '同意',
|
||||
leftBtnCallback: () {
|
||||
Get.back();
|
||||
Get.toNamed(Routes.meetingMainPage,
|
||||
arguments: {
|
||||
"roomNumber": state.meetingRooms.value[index].roomNum
|
||||
});
|
||||
},
|
||||
rightBtnCallback: () {
|
||||
PermissionService.requestPermissions().then((value) {
|
||||
if (value == true) {
|
||||
Get.back();
|
||||
Get.toNamed(Routes.meetingMainPage,
|
||||
arguments: {
|
||||
"roomNumber": state.meetingRooms.value[index].roomNum
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
|
@ -9,6 +10,7 @@ import 'package:wgshare/routes/app_routes.dart';
|
|||
import 'package:wgshare/utils/cus_behavior.dart';
|
||||
import 'package:wgshare/utils/toast_utils.dart';
|
||||
import '../../utils/color_util.dart';
|
||||
import '../../view/upgrade/loadJson/load_network_json.dart';
|
||||
import 'home_logic.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
|
|
@ -189,11 +191,7 @@ class HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin {
|
|||
),
|
||||
),
|
||||
onTap: () {
|
||||
Get.toNamed(Routes.meetingMainPage,
|
||||
arguments: {
|
||||
"roomNumber": state.meetingRooms
|
||||
.value[index].roomNum
|
||||
});
|
||||
logic.gotoMeetingRoom(context, index);
|
||||
},
|
||||
)
|
||||
],
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import 'dart:convert';
|
|||
import 'package:crypto/crypto.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:wgshare/common/mixins/request_tool_mixin.dart';
|
||||
import 'package:wgshare/utils/device_info.dart';
|
||||
import 'package:wgshare/utils/toast_utils.dart';
|
||||
|
|
@ -10,22 +11,31 @@ import 'package:wgshare/utils/toast_utils.dart';
|
|||
import '../../common/config/app_config.dart';
|
||||
import '../../common/models/common/base_structure_result.dart';
|
||||
import '../../common/models/user_info_entity.dart';
|
||||
import '../../common/store/app_storage_key.dart';
|
||||
import '../../common/store/user_store.dart';
|
||||
import '../../routes/app_routes.dart';
|
||||
import '../../utils/storage.dart';
|
||||
import '../../utils/permission/PermissionService.dart';
|
||||
import '../../view/public_dialog.dart';
|
||||
import '../../view/upgrade/loadJson/hide_load_network_json.dart';
|
||||
import '../../view/upgrade/loadJson/load_network_json.dart';
|
||||
import 'login_state.dart';
|
||||
|
||||
class LoginLogic extends GetxController with RequestToolMixin {
|
||||
final LoginState state = LoginState();
|
||||
late LoginState state;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
print("初始化登录init................");
|
||||
state = LoginState();
|
||||
HideCheckVersion hideCheckVersion = HideCheckVersion();
|
||||
hideCheckVersion.doHttpHideCheckVersion();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
print("销毁onClose................");
|
||||
|
||||
super.onClose();
|
||||
state.passwordController.dispose();
|
||||
state.userNameController.dispose();
|
||||
state.meetingCodeController.dispose();
|
||||
state.nickNameCodeController.dispose();
|
||||
}
|
||||
|
||||
/// 改变页面状态
|
||||
|
|
@ -40,23 +50,24 @@ class LoginLogic extends GetxController with RequestToolMixin {
|
|||
|
||||
/// 登录
|
||||
Future<void> doHttpLogin() async {
|
||||
if(state.userNameController.text.isEmpty){
|
||||
if(state.userNameController!.text.isEmpty){
|
||||
ToastUtils.showError("请输入账号");
|
||||
}else if(state.passwordController.text.isEmpty){
|
||||
}else if(state.passwordController!.text.isEmpty){
|
||||
ToastUtils.showError("请输入密码");
|
||||
}else if(state.checkAgreementBool.value != true){
|
||||
ToastUtils.showError("请阅读并勾选相关协议");
|
||||
}else{
|
||||
BaseStructureResult<UserInfoEntity> res = await getClient().login(state.userNameController.text, md5.convert(utf8.encode(state.passwordController.text)).toString());
|
||||
BaseStructureResult<UserInfoEntity> res = await getClient().login(state.userNameController!.text, md5.convert(utf8.encode(state.passwordController!.text)).toString());
|
||||
if (null != res.data) {
|
||||
UserStore.to.setToken(res.data!.token);
|
||||
UserStore.to.setRefreshToken(res.data!.refreshToken);
|
||||
UserStore.to.setUserDetailInfo(res.data!);
|
||||
UserStore.to.setLoginType(AppConfig.NORMAL_LOGIN);
|
||||
Get.offAllNamed(Routes.startPage);
|
||||
state.userNameController.text = "";
|
||||
state.passwordController.text = "";
|
||||
state.meetingCodeController.text = "";
|
||||
state.nickNameCodeController.text = "";
|
||||
state.userNameController!.text = "";
|
||||
state.passwordController!.text = "";
|
||||
state.meetingCodeController!.text = "";
|
||||
state.nickNameCodeController!.text = "";
|
||||
state.checkAgreementBool.value = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -64,25 +75,26 @@ class LoginLogic extends GetxController with RequestToolMixin {
|
|||
|
||||
/// 直接进入会议(匿名登录)
|
||||
Future<void> doHttpAnonymousLogin() async {
|
||||
if(state.meetingCodeController.text.isEmpty){
|
||||
if(state.meetingCodeController!.text.isEmpty){
|
||||
ToastUtils.showError("请输入会议号");
|
||||
}else if(state.meetingCodeController.text.length != 8){
|
||||
}else if(state.meetingCodeController!.text.length != 8){
|
||||
ToastUtils.showError("请输入正确的会议号");
|
||||
}else if(state.nickNameCodeController.text.isEmpty){
|
||||
}else if(state.nickNameCodeController!.text.isEmpty){
|
||||
ToastUtils.showError("请输入昵称");
|
||||
}else if(state.checkAgreementBool != true){
|
||||
ToastUtils.showError("请阅读并勾选相关协议");
|
||||
}else{
|
||||
BaseStructureResult<UserInfoEntity> res = await getClient().anonLogin(await DeviceInfo.getDeviceId(),state.nickNameCodeController.text, state.meetingCodeController.text);
|
||||
BaseStructureResult<UserInfoEntity> res = await getClient().anonLogin(await DeviceInfo.getDeviceId(),state.nickNameCodeController!.text, state.meetingCodeController!.text);
|
||||
if (null != res.data) {
|
||||
UserStore.to.setToken(res.data!.token);
|
||||
UserStore.to.setRefreshToken(res.data!.refreshToken);
|
||||
UserStore.to.setUserDetailInfo(res.data!);
|
||||
UserStore.to.setLoginType(AppConfig.ANONYMOUS_LOGIN);
|
||||
Get.toNamed(Routes.meetingMainPage, arguments: {"roomNumber": state.meetingCodeController.text});
|
||||
state.userNameController.text = "";
|
||||
state.passwordController.text = "";
|
||||
state.meetingCodeController.text = "";
|
||||
state.nickNameCodeController.text = "";
|
||||
Get.toNamed(Routes.meetingMainPage, arguments: {"roomNumber": state.meetingCodeController!.text});
|
||||
state.userNameController!.text = "";
|
||||
state.passwordController!.text = "";
|
||||
state.meetingCodeController!.text = "";
|
||||
state.nickNameCodeController!.text = "";
|
||||
state.checkAgreementBool.value = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -90,16 +102,16 @@ class LoginLogic extends GetxController with RequestToolMixin {
|
|||
|
||||
/// 检验房间
|
||||
Future<void> doHttpCheckMeetingRoom() async {
|
||||
if(state.meetingCodeController.text.isEmpty){
|
||||
if(state.meetingCodeController!.text.isEmpty){
|
||||
ToastUtils.showError("请输入会议号");
|
||||
}else if(state.meetingCodeController.text.length != 8){
|
||||
}else if(state.meetingCodeController!.text.length != 8){
|
||||
ToastUtils.showError("请输入正确的会议号");
|
||||
}else if(state.nickNameCodeController.text.isEmpty){
|
||||
}else if(state.nickNameCodeController!.text.isEmpty){
|
||||
ToastUtils.showError("请输入昵称");
|
||||
}else if(state.checkAgreementBool != true){
|
||||
ToastUtils.showError("请阅读并勾选相关协议");
|
||||
}else{
|
||||
BaseStructureResult<bool> res = await getClient().checkout(state.meetingCodeController.text);
|
||||
BaseStructureResult<bool> res = await getClient().checkout(state.meetingCodeController!.text);
|
||||
if (null != res.data) {
|
||||
if(res.data == true){
|
||||
doHttpAnonymousLogin();
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@ import 'package:get/get.dart';
|
|||
|
||||
class LoginState {
|
||||
|
||||
LoginState() {}
|
||||
TextEditingController? userNameController;
|
||||
TextEditingController? passwordController;
|
||||
TextEditingController? meetingCodeController;
|
||||
TextEditingController? nickNameCodeController;
|
||||
LoginState() {
|
||||
|
||||
}
|
||||
|
||||
late TextEditingController userNameController = TextEditingController();
|
||||
late TextEditingController passwordController = TextEditingController();
|
||||
late TextEditingController meetingCodeController = TextEditingController();
|
||||
late TextEditingController nickNameCodeController = TextEditingController();
|
||||
|
||||
/// 页面状态,0:账号,1:会议号
|
||||
late RxInt pageState = 0.obs;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:al_downloader/al_downloader.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
|
|
@ -22,6 +23,10 @@ class _LoginPageState extends State<LoginPage> {
|
|||
@override
|
||||
void initState() {
|
||||
Utils.hideKeyboard();
|
||||
state.userNameController = TextEditingController();
|
||||
state.passwordController = TextEditingController();
|
||||
state.meetingCodeController = TextEditingController();
|
||||
state.nickNameCodeController = TextEditingController();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
|
@ -39,7 +44,7 @@ class _LoginPageState extends State<LoginPage> {
|
|||
decoration: const BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage('assets/images/login_bg.png'),
|
||||
fit: BoxFit.fill,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
|
|
@ -195,12 +200,13 @@ class _LoginPageState extends State<LoginPage> {
|
|||
color: ColorUtil.Color_153_153_153),
|
||||
),
|
||||
child: TextField(
|
||||
obscureText: true,
|
||||
controller: state.passwordController,
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp,
|
||||
),
|
||||
inputFormatters: <TextInputFormatter>[
|
||||
FilteringTextInputFormatter.digitsOnly,
|
||||
FilteringTextInputFormatter.allow(RegExp("^[a-z0-9A-Z]+")),//只允许输入数字,字母
|
||||
LengthLimitingTextInputFormatter(20)
|
||||
//限制长度
|
||||
],
|
||||
|
|
@ -375,6 +381,7 @@ class _LoginPageState extends State<LoginPage> {
|
|||
),
|
||||
),
|
||||
onTap: () {
|
||||
ALDownloader.cancelAll();
|
||||
if (state.pageState.value == 0) {
|
||||
logic.doHttpLogin();
|
||||
} else {
|
||||
|
|
@ -391,4 +398,13 @@ class _LoginPageState extends State<LoginPage> {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
state.passwordController?.dispose();
|
||||
state.userNameController?.dispose();
|
||||
state.meetingCodeController?.dispose();
|
||||
state.nickNameCodeController?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ import 'package:flutter/cupertino.dart';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:signalr_core/signalr_core.dart';
|
||||
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||
import 'package:wgshare/common/store/user_store.dart';
|
||||
import 'package:wgshare/utils/count_microphone_volume.dart';
|
||||
import '../../common/config/request_config.dart';
|
||||
|
|
@ -16,6 +18,8 @@ import '../../common/models/common/base_structure_result.dart';
|
|||
import '../../common/models/meeting_room_info.dart';
|
||||
import '../../common/models/meeting_room_msg.dart';
|
||||
import '../../common/models/meeting_room_user.dart';
|
||||
import '../../common/store/business_store.dart';
|
||||
import '../../routes/app_routes.dart';
|
||||
import '../../utils/agora/AgoraUtil.dart';
|
||||
import '../../utils/permission/PermissionService.dart';
|
||||
import '../../utils/toast_utils.dart';
|
||||
|
|
@ -23,15 +27,258 @@ import 'meeting_main_state.dart';
|
|||
|
||||
class MeetingMainLogic extends GetxController with RequestToolMixin {
|
||||
final MeetingMainState state = MeetingMainState();
|
||||
late RtcEngineEventHandler _rtcEngineEventHandler;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
_rtcEngineEventHandler = RtcEngineEventHandler(
|
||||
// 错误回调
|
||||
onError: (ErrorCodeType err, String msg){
|
||||
debugPrint("wgs输出===:RTC-错误回调:${err}---${msg}");
|
||||
},
|
||||
|
||||
// 成功加入会议室回调
|
||||
onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
|
||||
state.isJoinSuccess.value = true;
|
||||
debugPrint("meeting流程====》3加入频道" );
|
||||
debugPrint("wgs输出===:RTC-自己加入会议室,ID:${connection.localUid}");
|
||||
},
|
||||
onRejoinChannelSuccess: (RtcConnection connection, int elapsed) {
|
||||
state.isJoinSuccess.value = true;
|
||||
debugPrint("meeting流程====》4加入频道" );
|
||||
debugPrint("wgs输出===:RTC-自己加入会议室,ID:${connection.localUid}");
|
||||
},
|
||||
// 成功离开会议室回调
|
||||
onLeaveChannel: (RtcConnection connection, RtcStats stats) {
|
||||
debugPrint("wgs输出===:RTC-自己离开会议室,ID:${connection.localUid}");
|
||||
},
|
||||
|
||||
// 远端用户或主播加入当前会议室回调-主播角色才能接收该回调
|
||||
onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
|
||||
debugPrint("wgs输出===:RTC-远端用户或主播加入会议室,用户或主机的ID:$remoteUid");
|
||||
},
|
||||
|
||||
// 远端用户或主播离开当前会议室回调-主播角色才能接收该回调
|
||||
onUserOffline: (RtcConnection connection, int remoteUid,
|
||||
UserOfflineReasonType reason) async {
|
||||
// 判断是否用户取消了共享
|
||||
if (remoteUid.toString().length == 9) {
|
||||
for (var i = 0; i < state.cacheUsers.value.length; i++) {
|
||||
if (remoteUid.toString() ==
|
||||
state.cacheUsers.value[i].screenShareId) {
|
||||
state.cacheUsers.value[i].enableShare = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
update();
|
||||
debugPrint("wgs输出===:RTC-远端用户或主播离开会议室,用户或主机的ID:$remoteUid");
|
||||
},
|
||||
|
||||
// 音频路由发生变化回调
|
||||
onAudioRoutingChanged: (int routing) {
|
||||
debugPrint("wgs输出===:RTC-音频路由切换:$routing");
|
||||
state.communicationMode.value = routing;
|
||||
if (routing == 1) {
|
||||
debugPrint("wgs输出===:RTC-音频路由切换为听筒");
|
||||
} else if (routing == 3) {
|
||||
debugPrint("wgs输出===:RTC-音频路由切换为扬声器");
|
||||
} else {
|
||||
debugPrint("wgs输出===:RTC-音频路由切换为外接设备");
|
||||
}
|
||||
},
|
||||
|
||||
// 音频采集开关回调
|
||||
onLocalAudioStateChanged: (RtcConnection connection,
|
||||
LocalAudioStreamState state, LocalAudioStreamReason reason) {
|
||||
debugPrint("wgs输出===:RTC-音频采集开关:$state");
|
||||
},
|
||||
|
||||
// 远端视频状态发生改变回调
|
||||
onRemoteVideoStateChanged: (RtcConnection connection,
|
||||
int remoteUid,
|
||||
RemoteVideoState remoteVideoState,
|
||||
RemoteVideoStateReason remoteVideoStateReason,
|
||||
int elapsed) {
|
||||
debugPrint(
|
||||
"wgs输出===:RTC-远端视频状态发生改变:ID-$remoteUid-状态-$remoteVideoStateReason");
|
||||
if (remoteVideoStateReason ==
|
||||
RemoteVideoStateReason.remoteVideoStateReasonRemoteMuted) {
|
||||
// 远端用户停止发送视频流或远端用户禁用视频模块
|
||||
if (remoteUid.toString().length != 9) {
|
||||
// 摄像头
|
||||
if (remoteUid.toString() == state.remoteUid.value) {
|
||||
// 如果停止发送视频流或禁用视频模块的远端用户是当前全员观看主播
|
||||
doHttpGetTvAnchor();
|
||||
}
|
||||
} else {
|
||||
// 共享屏幕(此版本不做)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 用户音量提示回调
|
||||
onAudioVolumeIndication: (RtcConnection connection,
|
||||
List<AudioVolumeInfo> speakers,
|
||||
int speakerNumber,
|
||||
int totalVolume) {
|
||||
if (speakers.isNotEmpty) {
|
||||
for (AudioVolumeInfo avi in speakers) {
|
||||
if (avi.uid == 0) {
|
||||
// debugPrint("wgs输出===:RTC-本地用户音量提示:${avi.uid}--${avi.volume}");
|
||||
for (MeetingRoomUser mru in state.cacheUsers.value) {
|
||||
if (UserStore.to.userInfoEntity.value!.uid == mru.uid) {
|
||||
mru.volume = CountMicrophoneVolume.getVolume(avi.volume!);
|
||||
state.microphoneVolume.value =
|
||||
CountMicrophoneVolume.getVolume(avi.volume!);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// debugPrint("wgs输出===:RTC-远端用户音量提示:${avi.uid}--${avi.volume}");
|
||||
for (MeetingRoomUser mru in state.cacheUsers.value) {
|
||||
mru.volume = CountMicrophoneVolume.getVolume(avi.volume!);
|
||||
|
||||
if (avi.volume != 0) {
|
||||
state.spokesman.value = mru.userName;
|
||||
state.spokesmanVolume.value =
|
||||
CountMicrophoneVolume.getVolume(avi.volume!);
|
||||
} else {
|
||||
state.spokesman.value = "";
|
||||
state.spokesmanVolume.value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*for (MeetingRoomUser mru in state.cacheUsers.value) {
|
||||
// 用于更改语音布局里的用户列表麦克风
|
||||
if (avi.uid == 0) {
|
||||
// debugPrint("wgs输出===:RTC-用户音量提示(自己):${CountMicrophoneVolume.getVolume(avi.volume!)}");
|
||||
mru.volume = CountMicrophoneVolume.getVolume(avi.volume!);
|
||||
state.microphoneVolume.value =
|
||||
CountMicrophoneVolume.getVolume(avi.volume!);
|
||||
} else {
|
||||
debugPrint("wgs输出===:RTC-用户音量提示:${avi.uid}--${mru.uid}");
|
||||
if (avi.uid.toString() == mru.uid) {
|
||||
debugPrint("wgs输出===:RTC-用户音量提示(远端用户):${speakers[0].uid}--${speakers[0].volume}");
|
||||
mru.volume = CountMicrophoneVolume.getVolume(avi.volume!);
|
||||
|
||||
if (avi.volume != 0) {
|
||||
state.spokesman.value = mru.userName;
|
||||
state.spokesmanVolume.value =
|
||||
CountMicrophoneVolume.getVolume(avi.volume!);
|
||||
} else {
|
||||
state.spokesman.value = "";
|
||||
state.spokesmanVolume.value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 切换用户角色回调
|
||||
onClientRoleChanged: (RtcConnection connection,
|
||||
ClientRoleType oldRole,
|
||||
ClientRoleType newRole,
|
||||
ClientRoleOptions newRoleOptions) {
|
||||
debugPrint(
|
||||
"wgs输出===:RTC-切换用户角色为:${newRole == ClientRoleType.clientRoleBroadcaster ? "主播" : "观众"}");
|
||||
},
|
||||
|
||||
// token即将在30秒内过期回调
|
||||
onTokenPrivilegeWillExpire: (RtcConnection connection, String token) {
|
||||
doHttpGetMeetingToken(false);
|
||||
},
|
||||
|
||||
// token已过期
|
||||
onRequestToken: (RtcConnection connection){
|
||||
doHttpGetMeetingToken(false);
|
||||
},
|
||||
|
||||
// 本地视频状态发生改变回调
|
||||
onLocalVideoStateChanged: (VideoSourceType source,
|
||||
LocalVideoStreamState state, LocalVideoStreamReason reason) {
|
||||
debugPrint("wgs输出===:RTC-本地视频状态发生改变:$source--$state--$reason");
|
||||
},
|
||||
|
||||
// 网络连接状态回调
|
||||
onConnectionStateChanged: (RtcConnection connection,
|
||||
ConnectionStateType stateType,
|
||||
ConnectionChangedReasonType reason) {
|
||||
debugPrint("wgs输出===:RTC-网络连接状态发生改变:"
|
||||
"会议室编号(${connection.channelId}),"
|
||||
"网络状态($stateType-${AgoraUtil.getConnectionStateChangedType(stateType)}),"
|
||||
"网络改变原因($reason-${AgoraUtil.getConnectionChangedReasonType(reason)})");
|
||||
if(reason == ConnectionChangedReasonType.connectionChangedTokenExpired){
|
||||
// 当前使用的token已过期
|
||||
doHttpGetMeetingToken(false);
|
||||
}else{
|
||||
if (stateType == ConnectionStateType.connectionStateReconnecting) {
|
||||
if (EasyLoading.isShow == false) {
|
||||
ToastUtils.showLoadingToMask(
|
||||
"网络故障,正在重连...", EasyLoadingMaskType.black);
|
||||
}
|
||||
} else if (stateType ==
|
||||
ConnectionStateType.connectionStateConnected &&
|
||||
reason ==
|
||||
ConnectionChangedReasonType
|
||||
.connectionChangedRejoinSuccess) {
|
||||
ToastUtils.dismiss();
|
||||
if (EasyLoading.isShow == false) {
|
||||
ToastUtils.showSuccessToMask(
|
||||
"重连成功!", EasyLoadingMaskType.black);
|
||||
}
|
||||
} else if (reason ==
|
||||
ConnectionChangedReasonType.connectionChangedLost) {
|
||||
// 和服务器失去连接后,再延迟15秒(和signalR Socket一致),让SDK继续重连,如果重连不上则告知用户需要重新加入
|
||||
Future.delayed(const Duration(milliseconds: 15000), () {
|
||||
ToastUtils.dismiss();
|
||||
if (state.isShowOkAlertDialog.value == false) {
|
||||
showOkAlertDialog(
|
||||
context: Get.context!,
|
||||
title: "提示",
|
||||
message: "网络错误,请重新加入会议室",
|
||||
okLabel: "确定",
|
||||
barrierDismissible: false,
|
||||
).then((OkCancelResult value) {
|
||||
Get.back();
|
||||
Get.back();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 渲染器已接收首帧远端视频回调
|
||||
onFirstRemoteVideoFrame: (RtcConnection connection, int remoteUid,
|
||||
int width, int height, int elapsed) async {
|
||||
debugPrint("wgs输出===:RTC-渲染器已接收首帧远端视频回调:${remoteUid}--${width}--${height}--${elapsed}");
|
||||
},
|
||||
|
||||
// 已接收到远端视频并完成解码回调
|
||||
onFirstRemoteVideoDecoded: (RtcConnection connection, int remoteUid,
|
||||
int width, int height, int elapsed) {
|
||||
debugPrint("wgs输出===:RTC-已接收到远端视频并完成解码回调:${remoteUid}--${width}--${height}--${elapsed}");
|
||||
}
|
||||
|
||||
// 获取设备权限出错回调
|
||||
/*onPermissionError: (PermissionType permissionType){
|
||||
debugPrint("wgs输出===:RTC-获取设备权限出错:$permissionType");
|
||||
if(permissionType == PermissionType.screenCapture){
|
||||
// 获取共享屏幕出错(此版本不做)
|
||||
state.isOpenShare.value = false;
|
||||
stopScreenCapture();
|
||||
}
|
||||
}*/
|
||||
);
|
||||
// 接收参数
|
||||
var data = Get.arguments;
|
||||
state.roomNumber.value = data["roomNumber"];
|
||||
|
||||
// 开启屏幕常亮
|
||||
WakelockPlus.enable();
|
||||
|
||||
doHttpGetMeetingToken(true);
|
||||
}
|
||||
|
||||
|
|
@ -43,6 +290,10 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
state.sendMsgController.dispose();
|
||||
state.pageController.dispose();
|
||||
stopTime();
|
||||
|
||||
// 关闭屏幕常亮
|
||||
WakelockPlus.disable();
|
||||
|
||||
leaveMeetingToRtc();
|
||||
leaveMeetingToSocket();
|
||||
}
|
||||
|
|
@ -53,10 +304,13 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
await getClient().getMeetingToken(state.roomNumber.value);
|
||||
state.meetingToken.value = res.data!;
|
||||
|
||||
if (isInit == true) {
|
||||
debugPrint("meeting流程====》1获取token成功" );
|
||||
|
||||
if (isInit) {
|
||||
signalRSocket();
|
||||
} else {
|
||||
initRtc();
|
||||
renewToken(state.meetingToken.value);
|
||||
// initRtc();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -78,6 +332,7 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
getMeetingRoomAllUser(results[1].data as List<MeetingRoomUser>);
|
||||
} finally {
|
||||
ToastUtils.dismiss();
|
||||
ToastUtils.showSuccess("${state.isJoinSuccess}--${state.rctEngine.value}--${state.users.isNotEmpty}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -150,6 +405,26 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
update();
|
||||
}
|
||||
|
||||
/// 点击grid切换大屏
|
||||
void checkLargeScreen(String uid) {
|
||||
ToastUtils.showSuccess("切换用户成功");
|
||||
if (uid == UserStore.to.userInfoEntity.value!.uid) {
|
||||
state.remoteUid.value = "0";
|
||||
state.remoteAssistantUid.value = "0";
|
||||
} else {
|
||||
if (state.isSpeak.value == true && state.isOpenCamera.value == true) {
|
||||
state.floating.value?.open(Get.context!);
|
||||
}
|
||||
state.remoteUid.value = uid;
|
||||
state.remoteAssistantUid.value = uid;
|
||||
}
|
||||
changePageState(0);
|
||||
Future.delayed(const Duration(milliseconds: 200), () {
|
||||
changePageState(1);
|
||||
});
|
||||
update();
|
||||
}
|
||||
|
||||
/// ------------------------------------------------------------------------------发言权限
|
||||
/// 申请发言权限
|
||||
Future<void> doHttpApplySpeak() async {
|
||||
|
|
@ -179,6 +454,10 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
/// ------------------------------------------------------------------------------麦克风相关(操作)
|
||||
/// 用户开闭麦
|
||||
Future<void> doHttpSetMicr(bool isOpenMicrophone) async {
|
||||
if (isOpenMicrophone == false) {
|
||||
state.spokesman.value = "";
|
||||
state.spokesmanVolume.value = 0;
|
||||
}
|
||||
await getClient().setMicr(state.roomNumber.value, isOpenMicrophone,
|
||||
UserStore.to.userInfoEntity.value!.uid);
|
||||
}
|
||||
|
|
@ -200,6 +479,7 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
BaseStructureResult res =
|
||||
await getClient().getTvAnchor(state.roomNumber.value);
|
||||
state.remoteUid.value = res.data!.toString();
|
||||
state.remoteAssistantUid.value = res.data!.toString();
|
||||
debugPrint("wgs输出===:获取当前全员观看主播${res.data}");
|
||||
|
||||
if (res.data!.toString().length != 9) {
|
||||
|
|
@ -252,11 +532,13 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
} else {
|
||||
// 当前会议室不存在全员观看主播时,设置主播ID为空并切换页面到视频状态
|
||||
debugPrint("wgs输出===:当前会议室不存在全员观看主播时,设置主播ID为空并切换页面到视频状态");
|
||||
state.remoteUid.value = "";
|
||||
// state.remoteUid.value = "";
|
||||
state.remoteAssistantUid.value = "";
|
||||
changePageState(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debugPrint("wgs输出===:当前全员观看是共享类型");
|
||||
if (state.remoteUid.value ==
|
||||
UserStore.to.userInfoEntity.value!.screenShareId) {
|
||||
// 如果是自己在共享
|
||||
|
|
@ -268,6 +550,7 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
state.cacheUsers.value[i].enableShare = true;
|
||||
}
|
||||
}
|
||||
changePageState(1);
|
||||
}
|
||||
}
|
||||
update();
|
||||
|
|
@ -339,6 +622,8 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
|
||||
await state.hubConnection.value?.start();
|
||||
|
||||
debugPrint("meeting流程====》2socket链接成功" );
|
||||
|
||||
// 开始重新连接时回调
|
||||
state.hubConnection.value?.onreconnecting((error) {
|
||||
debugPrint("wgs输出===:SignalR Socket-重连$error");
|
||||
|
|
@ -362,12 +647,21 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
debugPrint("wgs输出===:SignalR Socket-重连失败$error");
|
||||
ToastUtils.dismiss();
|
||||
|
||||
if (state.isNormaExit.value == false &&
|
||||
state.isShowOkAlertDialog.value == false) {
|
||||
debugPrint(
|
||||
"wgs输出===:SignalR Socket-重连打印1${state.isNormaExit.value == false && state.isShowOkAlertDialog.value == false}");
|
||||
debugPrint("wgs输出===:SignalR Socket-重连打印2${null != UserStore.to.token}");
|
||||
debugPrint(
|
||||
"wgs输出===:SignalR Socket-重连打印3${UserStore.to.token!.isNotEmpty}");
|
||||
debugPrint(
|
||||
"wgs输出===:SignalR Socket-重连打印4${(state.isNormaExit.value == false && state.isShowOkAlertDialog.value == false) || null != UserStore.to.token || UserStore.to.token!.isNotEmpty}");
|
||||
|
||||
if ((state.isNormaExit.value == false &&
|
||||
state.isShowOkAlertDialog.value == false) ||
|
||||
(state.isNormaExit.value == false && null != UserStore.to.token)) {
|
||||
showOkAlertDialog(
|
||||
context: Get.context!,
|
||||
title: "提示",
|
||||
message: "网络错误,请重新加入会议室",
|
||||
message: "网络错误,请重新加入会议室1",
|
||||
okLabel: "确定",
|
||||
barrierDismissible: false,
|
||||
).then((OkCancelResult value) {
|
||||
|
|
@ -536,7 +830,9 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
}
|
||||
state.users.value = state.cacheUsers.value;
|
||||
update();
|
||||
if (listDynamic[0] != UserStore.to.userInfoEntity.value!.uid) {
|
||||
doHttpGetTvAnchor();
|
||||
}
|
||||
debugPrint("wgs输出===:Socket-远端用户或主播离开会议室:$jsonStr");
|
||||
});
|
||||
|
||||
|
|
@ -562,6 +858,20 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
});
|
||||
});
|
||||
|
||||
/// 强制退出
|
||||
state.hubConnection.value?.on("ForceLogout", (e) {
|
||||
// var jsonStr = const Utf8Decoder().convert(json.encode(uid).runes.toList());
|
||||
var jsonStr = json.encode(e);
|
||||
List listDynamic = jsonDecode(jsonStr);
|
||||
debugPrint("wgs输出===:Socket-强制退出:${listDynamic[0]}");
|
||||
state.isNormaExit.value = true;
|
||||
ToastUtils.showSuccess("${listDynamic[0]}");
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
UserStore.to.erase();
|
||||
Get.offAllNamed(Routes.loginPage);
|
||||
});
|
||||
});
|
||||
|
||||
/// ------------------------------------------------------------------------------会议室聊天相关回调
|
||||
/// 会议室接收消息回调
|
||||
state.hubConnection.value?.on("ReceiveMessage", (e) {
|
||||
|
|
@ -572,10 +882,12 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
MeetingRoomMsg meetingRoomMsg = MeetingRoomMsg(list[0], list[1], list[2],
|
||||
0, formatDate(dateTime, [HH, ':', nn, ':', ss]));
|
||||
state.meetingRoomMsgs.value.add(meetingRoomMsg);
|
||||
state.msgNum.value = state.msgNum.value += 1;
|
||||
update();
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
state.chatController
|
||||
.jumpTo(state.chatController.position.maxScrollExtent);
|
||||
state.msgNum.value = 0;
|
||||
});
|
||||
debugPrint("wgs输出===:Socket-会议室接收消息:$jsonStr");
|
||||
});
|
||||
|
|
@ -588,13 +900,18 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
var listDynamic = jsonDecode(jsonStr);
|
||||
MeetingRoomUser meetingRoomUser = MeetingRoomUser.fromJson(listDynamic);
|
||||
if (meetingRoomUser.enableCamera == true) {
|
||||
debugPrint("wgs输出===:Socket-用户单独开摄像头");
|
||||
debugPrint("wgs输出===:Socket-用户单独开摄像头${jsonStr}");
|
||||
|
||||
// 遍历会议室用户列表,更改摄像头状态
|
||||
for (MeetingRoomUser mru in state.cacheUsers.value) {
|
||||
if (mru.uid == meetingRoomUser.uid) {
|
||||
mru.enableCamera = true;
|
||||
}
|
||||
debugPrint(
|
||||
"wgs输出===:Socket-用户单独开摄像头---${state.remoteUid.value}--${meetingRoomUser.uid}");
|
||||
if (state.remoteUid.value == meetingRoomUser.uid) {
|
||||
doHttpGetTvAnchor();
|
||||
}
|
||||
}
|
||||
|
||||
if (meetingRoomUser.uid == UserStore.to.userInfoEntity.value!.uid) {
|
||||
|
|
@ -630,14 +947,15 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
muteLocalVideoStream(true);
|
||||
// 停止本地预览
|
||||
stopPreview();
|
||||
// 当前全员观看主播是自己时
|
||||
if (state.remoteUid.value == "0") {
|
||||
state.remoteUid.value = "";
|
||||
}
|
||||
// 关闭本地预览悬浮窗
|
||||
if (state.floating.value?.isShowing == true) {
|
||||
state.floating.value?.close();
|
||||
}
|
||||
// 当前全员观看主播是自己时
|
||||
if (state.remoteUid.value == "0") {
|
||||
state.remoteUid.value = "";
|
||||
doHttpGetTvAnchor();
|
||||
}
|
||||
}
|
||||
}
|
||||
update();
|
||||
|
|
@ -656,8 +974,12 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
/// 加入会议室
|
||||
/// isAgain:是否重新加入
|
||||
Future<void> joinMeetingToSocket(bool isAgain) async {
|
||||
await state.hubConnection.value?.invoke("joinChannel",
|
||||
args: [state.roomNumber.value, false, false, false]);
|
||||
await state.hubConnection.value?.invoke("joinChannel", args: [
|
||||
state.roomNumber.value,
|
||||
state.isOpenMicrophone.value,
|
||||
state.isOpenCamera.value,
|
||||
state.isSpeak.value
|
||||
]);
|
||||
mergeFetch(isAgain);
|
||||
/*if(isAgain == false){
|
||||
mergeFetch(isAgain);
|
||||
|
|
@ -696,11 +1018,10 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
/// ------------------------------------------------------------------------------声网SDK相关
|
||||
/// 初始化声网SDK
|
||||
Future<void> initRtc() async {
|
||||
// 请求麦克风、摄像头权限
|
||||
PermissionService.requestPermissions();
|
||||
|
||||
// 创建 RtcEngine 对象
|
||||
state.rctEngine.value = createAgoraRtcEngineEx();
|
||||
await leaveMeetingToRtc();
|
||||
|
||||
state.rctEngine.value = createAgoraRtcEngine();
|
||||
|
||||
// 初始化 RtcEngine,设置频道场景为 channelProfileLiveBroadcasting(直播场景)
|
||||
await state.rctEngine.value?.initialize(RtcEngineContext(
|
||||
|
|
@ -708,10 +1029,12 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
channelProfile: ChannelProfileType.channelProfileLiveBroadcasting,
|
||||
// logConfig:const LogConfig()
|
||||
));
|
||||
state.rctEngine.value?.registerEventHandler(_rtcEngineEventHandler);
|
||||
|
||||
// 音频模块默认启动,所以这里不再调用启动方法
|
||||
|
||||
// 启用视频模块
|
||||
enableVideo();
|
||||
await enableVideo();
|
||||
// 设置默认音频路由为听筒
|
||||
await state.rctEngine.value?.setDefaultAudioRouteToSpeakerphone(false);
|
||||
// 打开用户音量回调
|
||||
|
|
@ -721,191 +1044,12 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
await state.rctEngine.value
|
||||
?.setDualStreamMode(mode: SimulcastStreamMode.enableSimulcastStream);
|
||||
|
||||
joinMeetingToRtc();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_)=>joinMeetingToRtc());
|
||||
|
||||
// 回调
|
||||
state.rctEngine.value?.registerEventHandler(
|
||||
RtcEngineEventHandler(
|
||||
// 成功加入会议室回调
|
||||
onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
|
||||
state.isJoinSuccess.value = true;
|
||||
debugPrint("wgs输出===:RTC-自己加入会议室,ID:${connection.localUid}");
|
||||
},
|
||||
|
||||
// 成功离开会议室回调
|
||||
onLeaveChannel: (RtcConnection connection, RtcStats stats) {
|
||||
debugPrint("wgs输出===:RTC-自己离开会议室,ID:${connection.localUid}");
|
||||
},
|
||||
// await joinMeetingToRtc();
|
||||
|
||||
// 远端用户或主播加入当前会议室回调-主播角色才能接收该回调
|
||||
onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
|
||||
debugPrint("wgs输出===:RTC-远端用户或主播加入会议室,用户或主机的ID:$remoteUid");
|
||||
},
|
||||
|
||||
// 远端用户或主播离开当前会议室回调-主播角色才能接收该回调
|
||||
onUserOffline: (RtcConnection connection, int remoteUid,
|
||||
UserOfflineReasonType reason) async {
|
||||
// 判断是否用户取消了共享
|
||||
if (remoteUid.toString().length == 9) {
|
||||
for (var i = 0; i < state.cacheUsers.value.length; i++) {
|
||||
if (remoteUid.toString() ==
|
||||
state.cacheUsers.value[i].screenShareId) {
|
||||
state.cacheUsers.value[i].enableShare = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
update();
|
||||
debugPrint("wgs输出===:RTC-远端用户或主播离开会议室,用户或主机的ID:$remoteUid");
|
||||
},
|
||||
|
||||
// 音频路由发生变化回调
|
||||
onAudioRoutingChanged: (int routing) {
|
||||
debugPrint("wgs输出===:RTC-音频路由切换:$routing");
|
||||
state.communicationMode.value = routing;
|
||||
if (routing == 1) {
|
||||
debugPrint("wgs输出===:RTC-音频路由切换为听筒");
|
||||
} else if (routing == 3) {
|
||||
debugPrint("wgs输出===:RTC-音频路由切换为扬声器");
|
||||
} else {
|
||||
debugPrint("wgs输出===:RTC-音频路由切换为外接设备");
|
||||
}
|
||||
},
|
||||
|
||||
// 音频采集开关回调
|
||||
onLocalAudioStateChanged: (RtcConnection connection,
|
||||
LocalAudioStreamState state, LocalAudioStreamReason reason) {
|
||||
debugPrint("wgs输出===:RTC-音频采集开关:$state");
|
||||
},
|
||||
|
||||
// 远端视频状态发生改变回调
|
||||
onRemoteVideoStateChanged: (RtcConnection connection,
|
||||
int remoteUid,
|
||||
RemoteVideoState remoteVideoState,
|
||||
RemoteVideoStateReason remoteVideoStateReason,
|
||||
int elapsed) {
|
||||
debugPrint(
|
||||
"wgs输出===:RTC-远端视频状态发生改变:ID-$remoteUid-状态-$remoteVideoStateReason");
|
||||
if (remoteVideoStateReason ==
|
||||
RemoteVideoStateReason.remoteVideoStateReasonRemoteMuted) {
|
||||
// 远端用户停止发送视频流或远端用户禁用视频模块
|
||||
if (remoteUid.toString().length != 9) {
|
||||
// 摄像头
|
||||
if (remoteUid.toString() == state.remoteUid.value) {
|
||||
// 如果停止发送视频流或禁用视频模块的远端用户是当前全员观看主播
|
||||
doHttpGetTvAnchor();
|
||||
}
|
||||
} else {
|
||||
// 共享屏幕(此版本不做)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 用户音量提示回调
|
||||
onAudioVolumeIndication: (RtcConnection connection,
|
||||
List<AudioVolumeInfo> speakers,
|
||||
int speakerNumber,
|
||||
int totalVolume) {
|
||||
if (speakers.isNotEmpty) {
|
||||
for (AudioVolumeInfo avi in speakers) {
|
||||
for (MeetingRoomUser mru in state.cacheUsers.value) {
|
||||
// 用于更改语音布局里的用户列表麦克风
|
||||
if (avi.uid == 0) {
|
||||
//debugPrint("wgs输出===:RTC-用户音量提示(自己):${CountMicrophoneVolume.getVolume(avi.volume!)}");
|
||||
mru.volume = CountMicrophoneVolume.getVolume(avi.volume!);
|
||||
state.microphoneVolume.value =
|
||||
CountMicrophoneVolume.getVolume(avi.volume!);
|
||||
} else {
|
||||
if (avi.uid.toString() == mru.uid) {
|
||||
//debugPrint("wgs输出===:RTC-用户音量提示(远端用户):${speakers[0].uid}--${speakers[0].volume}");
|
||||
mru.volume = CountMicrophoneVolume.getVolume(avi.volume!);
|
||||
|
||||
if (avi.volume != 0) {
|
||||
state.spokesman.value = mru.userName;
|
||||
state.spokesmanVolume.value =
|
||||
CountMicrophoneVolume.getVolume(avi.volume!);
|
||||
} else {
|
||||
state.spokesman.value = "";
|
||||
state.spokesmanVolume.value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 切换用户角色回调
|
||||
onClientRoleChanged: (RtcConnection connection,
|
||||
ClientRoleType oldRole,
|
||||
ClientRoleType newRole,
|
||||
ClientRoleOptions newRoleOptions) {
|
||||
debugPrint(
|
||||
"wgs输出===:RTC-切换用户角色为:${newRole == ClientRoleType.clientRoleBroadcaster ? "主播" : "观众"}");
|
||||
},
|
||||
|
||||
// token即将在30秒内过期回调
|
||||
onTokenPrivilegeWillExpire: (RtcConnection connection, String token) {
|
||||
doHttpGetMeetingToken(false);
|
||||
},
|
||||
|
||||
// 本地视频状态发生改变回调
|
||||
onLocalVideoStateChanged: (VideoSourceType source,
|
||||
LocalVideoStreamState state, LocalVideoStreamReason reason) {
|
||||
debugPrint("wgs输出===:RTC-本地视频状态发生改变:$source--$state--$reason");
|
||||
},
|
||||
|
||||
// 网络连接状态回调
|
||||
onConnectionStateChanged: (RtcConnection connection,
|
||||
ConnectionStateType stateType,
|
||||
ConnectionChangedReasonType reason) {
|
||||
debugPrint("wgs输出===:RTC-网络连接状态发生改变:"
|
||||
"会议室编号(${connection.channelId}),"
|
||||
"网络状态($stateType-${AgoraUtil.getConnectionStateChangedType(stateType)}),"
|
||||
"网络改变原因($reason-${AgoraUtil.getConnectionChangedReasonType(reason)})");
|
||||
if (stateType == ConnectionStateType.connectionStateReconnecting) {
|
||||
if (EasyLoading.isShow == false) {
|
||||
ToastUtils.showLoadingToMask(
|
||||
"网络故障,正在重连...", EasyLoadingMaskType.black);
|
||||
}
|
||||
} else if (stateType == ConnectionStateType.connectionStateConnected &&
|
||||
reason ==
|
||||
ConnectionChangedReasonType.connectionChangedRejoinSuccess) {
|
||||
ToastUtils.dismiss();
|
||||
if (EasyLoading.isShow == false) {
|
||||
ToastUtils.showSuccessToMask("重连成功!", EasyLoadingMaskType.black);
|
||||
}
|
||||
} else if (reason ==
|
||||
ConnectionChangedReasonType.connectionChangedLost) {
|
||||
// 和服务器失去连接后,再延迟15秒(和signalR Socket一致),让SDK继续重连,如果重连不上则告知用户需要重新加入
|
||||
Future.delayed(const Duration(milliseconds: 15000), () {
|
||||
ToastUtils.dismiss();
|
||||
if (state.isShowOkAlertDialog.value == false) {
|
||||
showOkAlertDialog(
|
||||
context: Get.context!,
|
||||
title: "提示",
|
||||
message: "网络错误,请重新加入会议室",
|
||||
okLabel: "确定",
|
||||
barrierDismissible: false,
|
||||
).then((OkCancelResult value) {
|
||||
Get.back();
|
||||
Get.back();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 获取设备权限出错回调
|
||||
/*onPermissionError: (PermissionType permissionType){
|
||||
debugPrint("wgs输出===:RTC-获取设备权限出错:$permissionType");
|
||||
if(permissionType == PermissionType.screenCapture){
|
||||
// 获取共享屏幕出错(此版本不做)
|
||||
state.isOpenShare.value = false;
|
||||
stopScreenCapture();
|
||||
}
|
||||
}*/
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 加入会议室
|
||||
|
|
@ -933,6 +1077,7 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
|
||||
/// 离开会议室
|
||||
Future<void> leaveMeetingToRtc() async {
|
||||
state.rctEngine.value?.unregisterEventHandler(_rtcEngineEventHandler);
|
||||
// 离开
|
||||
await state.rctEngine.value?.leaveChannel();
|
||||
// 释放资源
|
||||
|
|
@ -986,4 +1131,9 @@ class MeetingMainLogic extends GetxController with RequestToolMixin {
|
|||
Future<void> switchCamera() async {
|
||||
await state.rctEngine.value?.switchCamera();
|
||||
}
|
||||
|
||||
/// 更新 Token
|
||||
Future<void> renewToken(String token) async {
|
||||
await state.rctEngine.value?.renewToken(token);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@ class MeetingMainState {
|
|||
/// 会议室token
|
||||
late RxString meetingToken = "".obs;
|
||||
|
||||
/// 麦克风摄像头权限是否申请成功
|
||||
late RxBool isCameraToMicrophonePermissions = false.obs;
|
||||
|
||||
/// 会议室信息
|
||||
late Rx<MeetingRoomInfo?> meetingRoomInfo = Rx(null);
|
||||
/// 是否弹出showOkAlertDialog
|
||||
|
|
@ -76,6 +79,8 @@ class MeetingMainState {
|
|||
late RxBool isOpenShare = false.obs;
|
||||
/// 当前视频主播ID
|
||||
late RxString remoteUid = "".obs;
|
||||
/// 当前视频主播ID-辅助判断用
|
||||
late RxString remoteAssistantUid = "".obs;
|
||||
/// 是否成功加入会议室
|
||||
late RxBool isJoinSuccess = false.obs;
|
||||
|
||||
|
|
@ -87,13 +92,16 @@ class MeetingMainState {
|
|||
/// 聊天数据
|
||||
late RxList<MeetingRoomMsg> meetingRoomMsgs = RxList([]);
|
||||
|
||||
/// 聊天消息未读数量
|
||||
late RxInt msgNum = 0.obs;
|
||||
|
||||
/// signalR 长连接相关
|
||||
late RxString serviceUrl = "http://192.168.2.9:5192/session-manage".obs;
|
||||
late Rx<HubConnection?> hubConnection = Rx(null);
|
||||
|
||||
/// 声网相关
|
||||
final String appId = "4a4f7be64fa1404ebda74784fe9ac381";
|
||||
late Rx<RtcEngineEx?> rctEngine = Rx(null);
|
||||
Rx<RtcEngine?> rctEngine = Rx<RtcEngine?>(null);
|
||||
/// 是否自动订阅所有视频流
|
||||
late RxBool isAutoSubscribeVideo = false.obs;
|
||||
/// 是否自动订阅所有音频流
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import 'package:flutter_floating/floating/floating.dart';
|
|||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:liquid_progress_indicator_v2/liquid_progress_indicator.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:preload_page_view/preload_page_view.dart';
|
||||
import 'package:wgshare/common/config/app_config.dart';
|
||||
import 'package:wgshare/common/store/user_store.dart';
|
||||
|
|
@ -16,6 +17,8 @@ import 'package:wgshare/utils/toast_utils.dart';
|
|||
|
||||
import '../../utils/color_util.dart';
|
||||
import '../../utils/cus_behavior.dart';
|
||||
import '../../utils/permission/PermissionService.dart';
|
||||
import '../../view/public_dialog.dart';
|
||||
import '../../view/view_svg_path.dart';
|
||||
import 'meeting_main_logic.dart';
|
||||
import 'meeting_main_state.dart';
|
||||
|
|
@ -65,7 +68,9 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
),
|
||||
backgroundColor: ColorUtil.Color_41_41_41,
|
||||
),
|
||||
body: Obx(() => Stack(
|
||||
body: Obx((){
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
|
|
@ -83,7 +88,7 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
width: 92.w,
|
||||
child: Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
/*GestureDetector(
|
||||
child: Image.asset(
|
||||
'assets/images/meeting_main_narrow.png',
|
||||
width: 20.w,
|
||||
|
|
@ -91,8 +96,11 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
),
|
||||
onTap: () {},
|
||||
),
|
||||
SizedBox(width: 16.w),
|
||||
SizedBox(width: 16.w),*/
|
||||
GestureDetector(
|
||||
child: Container(
|
||||
color: ColorUtil.Color_0_0_0_0,
|
||||
padding: const EdgeInsets.only(top: 10, bottom: 10, right: 12),
|
||||
child: Image.asset(
|
||||
state.communicationMode.value == 1
|
||||
? 'assets/images/meeting_main_receiver.png'
|
||||
|
|
@ -100,9 +108,12 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
width: 20.w,
|
||||
height: 20.h,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
if (state.communicationMode.value == 1 ||
|
||||
state.communicationMode.value == 3) {
|
||||
if (state.communicationMode.value ==
|
||||
1 ||
|
||||
state.communicationMode.value ==
|
||||
3) {
|
||||
logic.changeMeetingAudioState(true);
|
||||
}
|
||||
},
|
||||
|
|
@ -129,13 +140,16 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
),
|
||||
),
|
||||
GestureDetector(
|
||||
child: Container(
|
||||
color: ColorUtil.Color_0_0_0_0,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
state.meetingRoomInfo.value?.roomName ??
|
||||
state.meetingRoomInfo.value
|
||||
?.roomName ??
|
||||
'',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
|
|
@ -160,6 +174,7 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
logic.changeMeetingInfoState(true);
|
||||
},
|
||||
|
|
@ -171,11 +186,15 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
children: [
|
||||
/// 退出会议
|
||||
GestureDetector(
|
||||
child: Container(
|
||||
color: ColorUtil.Color_0_0_0_0,
|
||||
padding: const EdgeInsets.only(top: 10, bottom: 10, left: 20),
|
||||
child: Image.asset(
|
||||
'assets/images/meeting_leave.png',
|
||||
width: 20.w,
|
||||
height: 20.h,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
Get.bottomSheet(
|
||||
isScrollControlled: true,
|
||||
|
|
@ -203,29 +222,38 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
// 视频-共享
|
||||
Visibility(
|
||||
visible: state.pageState.value == 1,
|
||||
child: state.isJoinSuccess.value == true && null != state.rctEngine.value && null != state.users.value && state.users.value.isNotEmpty
|
||||
child: state.isJoinSuccess.value == true &&
|
||||
null != state.rctEngine.value &&
|
||||
state.users.isNotEmpty
|
||||
? Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
PreloadPageView.builder(
|
||||
preloadPagesCount: 2,
|
||||
itemCount: 2,
|
||||
itemBuilder: (BuildContext context,
|
||||
itemBuilder:
|
||||
(BuildContext context,
|
||||
int position) =>
|
||||
returnPage(position),
|
||||
controller: PreloadPageController(
|
||||
controller:
|
||||
PreloadPageController(
|
||||
initialPage: 0),
|
||||
onPageChanged: (int position) {
|
||||
state.pageIndex.value = position;
|
||||
if (state.isSpeak.value == true &&
|
||||
state.isOpenCamera.value ==
|
||||
state.pageIndex.value =
|
||||
position;
|
||||
if (state.isSpeak.value ==
|
||||
true &&
|
||||
state.remoteUid.value != "0") {
|
||||
state.isOpenCamera
|
||||
.value ==
|
||||
true &&
|
||||
state.remoteUid.value !=
|
||||
"0") {
|
||||
if (position == 0) {
|
||||
state.floating.value
|
||||
?.open(context);
|
||||
} else {
|
||||
state.floating.value?.close();
|
||||
state.floating.value
|
||||
?.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -239,12 +267,13 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
Container(
|
||||
width: 8.w,
|
||||
height: 8.h,
|
||||
margin: const EdgeInsets.only(
|
||||
margin:
|
||||
const EdgeInsets.only(
|
||||
right: 6),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius.circular(
|
||||
8),
|
||||
BorderRadius
|
||||
.circular(8),
|
||||
color: state.pageIndex
|
||||
.value ==
|
||||
0
|
||||
|
|
@ -256,12 +285,13 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
Container(
|
||||
width: 8.w,
|
||||
height: 8.h,
|
||||
margin: const EdgeInsets.only(
|
||||
margin:
|
||||
const EdgeInsets.only(
|
||||
left: 6),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius.circular(
|
||||
8),
|
||||
BorderRadius
|
||||
.circular(8),
|
||||
color: state.pageIndex
|
||||
.value ==
|
||||
1
|
||||
|
|
@ -281,7 +311,8 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
)),
|
||||
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
GestureDetector(
|
||||
child: Container(
|
||||
|
|
@ -289,7 +320,8 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
height: 40.h,
|
||||
margin: const EdgeInsets.only(
|
||||
left: 20, bottom: 40),
|
||||
padding: const EdgeInsets.only(left: 20),
|
||||
padding:
|
||||
const EdgeInsets.only(left: 20),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(56),
|
||||
|
|
@ -298,12 +330,16 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
color: ColorUtil.Color_35_35_35_07,
|
||||
border: Border.all(
|
||||
width: 1.w,
|
||||
color: ColorUtil.Color_99_111_158),
|
||||
color:
|
||||
ColorUtil.Color_99_111_158),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/meeting_main_chat.png',
|
||||
|
|
@ -315,7 +351,30 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
'说点什么...',
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp,
|
||||
color: ColorUtil.Color_156_156_156),
|
||||
color: ColorUtil
|
||||
.Color_156_156_156),
|
||||
)
|
||||
],
|
||||
),
|
||||
Visibility(
|
||||
visible: state.msgNum.value > 0 ? true : false,
|
||||
child: Container(
|
||||
width: 18.w,
|
||||
height: 18.h,
|
||||
alignment: Alignment.center,
|
||||
margin: const EdgeInsets.only(right: 12),
|
||||
decoration: const BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||
color: ColorUtil.Color_255_69_69,
|
||||
),
|
||||
child: Text(
|
||||
"${state.msgNum.value}",
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
color: ColorUtil
|
||||
.Color_255_255_255),
|
||||
)
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
@ -324,8 +383,12 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
Get.bottomSheet(
|
||||
isScrollControlled: true,
|
||||
chatBottomSheet(context));
|
||||
|
||||
state.msgNum.value = 0;
|
||||
|
||||
Future.delayed(
|
||||
const Duration(milliseconds: 100), () {
|
||||
const Duration(milliseconds: 100),
|
||||
() {
|
||||
state.chatController.jumpTo(state
|
||||
.chatController
|
||||
.position
|
||||
|
|
@ -350,7 +413,8 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
'结束发言',
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp,
|
||||
color: ColorUtil.Color_255_255_255),
|
||||
color: ColorUtil
|
||||
.Color_255_255_255),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
|
|
@ -375,6 +439,9 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
children: [
|
||||
/// 音频
|
||||
GestureDetector(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(left: 6,right: 6),
|
||||
color: ColorUtil.Color_0_0_0_0,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
|
|
@ -382,7 +449,8 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
? Image.asset(
|
||||
state.isSpeak.value == false
|
||||
? 'assets/images/meeting_main_sqfy.png'
|
||||
: state.isOpenMicrophone.value ==
|
||||
: state.isOpenMicrophone
|
||||
.value ==
|
||||
true
|
||||
? 'assets/images/meeting_main_microphone_default.png'
|
||||
: 'assets/images/meeting_main_sqfy.png',
|
||||
|
|
@ -395,13 +463,14 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
height: 20.h,
|
||||
child: LiquidCustomProgressIndicator(
|
||||
value: state
|
||||
.microphoneVolume.value,
|
||||
.microphoneVolume
|
||||
.value,
|
||||
valueColor:
|
||||
const AlwaysStoppedAnimation(
|
||||
ColorUtil
|
||||
.Color_2_177_136),
|
||||
backgroundColor:
|
||||
ColorUtil.Color_255_255_255,
|
||||
backgroundColor: ColorUtil
|
||||
.Color_255_255_255,
|
||||
direction: Axis.vertical,
|
||||
shapePath: ViewSvgPath
|
||||
.getMicrpphonePath()),
|
||||
|
|
@ -415,7 +484,8 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
Text(
|
||||
state.isSpeak.value == false
|
||||
? '申请发言'
|
||||
: state.isOpenMicrophone.value == true
|
||||
: state.isOpenMicrophone.value ==
|
||||
true
|
||||
? "手动静音"
|
||||
: "解除静音",
|
||||
style: TextStyle(
|
||||
|
|
@ -424,6 +494,7 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
if (state.isSpeak.value == false) {
|
||||
Get.bottomSheet(
|
||||
|
|
@ -431,7 +502,8 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
applySpeakPermissionBottomSheet(
|
||||
context, 1));
|
||||
} else {
|
||||
if (state.isOpenMicrophone.value == false) {
|
||||
if (state.isOpenMicrophone.value ==
|
||||
false) {
|
||||
logic.doHttpSetMicr(true);
|
||||
} else {
|
||||
logic.doHttpSetMicr(false);
|
||||
|
|
@ -442,6 +514,9 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
|
||||
/// 视频
|
||||
GestureDetector(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(left: 6,right: 6),
|
||||
color: ColorUtil.Color_0_0_0_0,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
|
|
@ -468,6 +543,7 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
if (state.isSpeak.value == false) {
|
||||
Get.bottomSheet(
|
||||
|
|
@ -520,6 +596,9 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
|
||||
/// 成员
|
||||
GestureDetector(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(left: 6,right: 6),
|
||||
color: ColorUtil.Color_0_0_0_0,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
|
|
@ -537,6 +616,7 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
Get.bottomSheet(
|
||||
isScrollControlled: true,
|
||||
|
|
@ -552,9 +632,9 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
meetingInfoFloatingLayer(),
|
||||
meetingAudioFloatingLayer(),
|
||||
],
|
||||
))),
|
||||
)
|
||||
);
|
||||
}),),
|
||||
));
|
||||
}
|
||||
|
||||
/// 退出会议底部弹窗
|
||||
|
|
@ -672,7 +752,10 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
fontWeight: FontWeight.w500,
|
||||
color: ColorUtil.Color_134_134_134),
|
||||
),
|
||||
Row(
|
||||
GestureDetector(
|
||||
child: Container(
|
||||
color: ColorUtil.Color_0_0_0_0,
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
state.roomNumber.value,
|
||||
|
|
@ -681,13 +764,19 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
color: ColorUtil.Color_202_202_202,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
SizedBox(width: 12.w),
|
||||
const SizedBox(width: 12),
|
||||
Image.asset(
|
||||
'assets/images/meeting_main_copy.png',
|
||||
width: 18.w,
|
||||
height: 18.h,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: (){
|
||||
Clipboard.setData(ClipboardData(text: state.roomNumber.value));
|
||||
ToastUtils.showSuccess("复制成功");
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
@ -710,12 +799,19 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
fontWeight: FontWeight.w500,
|
||||
color: ColorUtil.Color_134_134_134),
|
||||
),
|
||||
Text(
|
||||
Container(
|
||||
width: 100,
|
||||
margin: const EdgeInsets.only(left: 6),
|
||||
alignment: Alignment.centerRight,
|
||||
child: Text(
|
||||
UserStore.to.userInfoEntity.value!.userName,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
color: ColorUtil.Color_202_202_202,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
@ -751,6 +847,7 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
SizedBox(height: 10.h),
|
||||
GestureDetector(
|
||||
child: Container(
|
||||
color: ColorUtil.Color_0_0_0_0,
|
||||
padding: const EdgeInsets.only(top: 10, bottom: 10),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
|
|
@ -811,7 +908,6 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
color: ColorUtil.Color_57_57_57_08,
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.only(top: 16, bottom: 16),
|
||||
margin: const EdgeInsets.only(left: 40, right: 40),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(6)),
|
||||
|
|
@ -841,8 +937,8 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
List<Widget> audioList() {
|
||||
List<Widget> audioList = [];
|
||||
audioList.add(GestureDetector(
|
||||
child: Column(children: [
|
||||
Text(
|
||||
child: Container(
|
||||
child: Text(
|
||||
'听筒',
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp,
|
||||
|
|
@ -853,22 +949,24 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
? ColorUtil.Color_85_117_242
|
||||
: ColorUtil.Color_134_134_134),
|
||||
),
|
||||
Container(
|
||||
color: ColorUtil.Color_0_0_0_0,
|
||||
width: double.infinity,
|
||||
height: 1.h,
|
||||
color: ColorUtil.Color_49_47_47,
|
||||
margin: const EdgeInsets.only(top: 14, bottom: 14),
|
||||
)
|
||||
]),
|
||||
height: 46.h,
|
||||
alignment: Alignment.center,
|
||||
),
|
||||
onTap: () {
|
||||
logic.setEnableSpeakerphone(1);
|
||||
logic.changeMeetingAudioState(false);
|
||||
},
|
||||
));
|
||||
audioList.add(Container(
|
||||
width: double.infinity,
|
||||
height: 1.h,
|
||||
color: ColorUtil.Color_49_47_47,
|
||||
));
|
||||
audioList.add(GestureDetector(
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
child: Container(
|
||||
child: Text(
|
||||
'扬声器',
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp,
|
||||
|
|
@ -879,7 +977,10 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
? ColorUtil.Color_85_117_242
|
||||
: ColorUtil.Color_134_134_134),
|
||||
),
|
||||
],
|
||||
color: ColorUtil.Color_0_0_0_0,
|
||||
width: double.infinity,
|
||||
height: 46.h,
|
||||
alignment: Alignment.center,
|
||||
),
|
||||
onTap: () {
|
||||
logic.setEnableSpeakerphone(3);
|
||||
|
|
@ -989,9 +1090,32 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
),
|
||||
),
|
||||
onTap: () {
|
||||
PermissionService.checkPermission(permissionList: [Permission.microphone,Permission.camera]).then((value){
|
||||
if(value == true){
|
||||
state.defaulOpenState.value = defaulOpenState;
|
||||
logic.doHttpApplySpeak();
|
||||
Get.back();
|
||||
}else{
|
||||
publicDialog(context,
|
||||
hideCancelBtn: true,
|
||||
title: '请求权限说明',
|
||||
describe:
|
||||
'申请发言需要获取您的麦克风以及摄像头权限,用以确保能够正常进行会议。',
|
||||
leftBtnStr: '拒绝',
|
||||
rightBtnStr: '同意',
|
||||
leftBtnCallback: () {
|
||||
}, rightBtnCallback: () {
|
||||
PermissionService.requestPermissions();
|
||||
/*PermissionService.requestPermissions().then((value){
|
||||
if(value == true){
|
||||
state.defaulOpenState.value = defaulOpenState;
|
||||
logic.doHttpApplySpeak();
|
||||
Get.back();
|
||||
}
|
||||
});*/
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
)
|
||||
|
|
@ -1156,7 +1280,8 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
style: TextStyle(
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: ColorUtil.Color_243_243_243),
|
||||
color:
|
||||
ColorUtil.Color_243_243_243),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8.w),
|
||||
|
|
@ -1200,7 +1325,8 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
children: [
|
||||
Container(
|
||||
child: Image.asset(
|
||||
state.users.value[index].enableShare ==
|
||||
state.users.value[index]
|
||||
.enableShare ==
|
||||
true
|
||||
? 'assets/images/meeting_main_share_currently.png'
|
||||
: 'assets/images/meeting_main_share_currently_n.png',
|
||||
|
|
@ -1393,13 +1519,14 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
TextSpan(
|
||||
text: state.meetingRoomMsgs.value[index].userName,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp, color: ColorUtil.Color_202_202_202),
|
||||
fontSize: 12.sp,
|
||||
color: ColorUtil.Color_202_202_202),
|
||||
),
|
||||
TextSpan(
|
||||
text: " ${state.meetingRoomMsgs.value[index].time}",
|
||||
style: TextStyle(
|
||||
fontSize: 10.sp, color: ColorUtil.Color_202_202_202
|
||||
),
|
||||
fontSize: 10.sp,
|
||||
color: ColorUtil.Color_202_202_202),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -1452,13 +1579,14 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
TextSpan(
|
||||
text: "${state.meetingRoomMsgs.value[index].time} ",
|
||||
style: TextStyle(
|
||||
fontSize: 10.sp, color: ColorUtil.Color_202_202_202
|
||||
),
|
||||
fontSize: 10.sp,
|
||||
color: ColorUtil.Color_202_202_202),
|
||||
),
|
||||
TextSpan(
|
||||
text: state.meetingRoomMsgs.value[index].userName,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp, color: ColorUtil.Color_202_202_202),
|
||||
fontSize: 12.sp,
|
||||
color: ColorUtil.Color_202_202_202),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -1565,7 +1693,7 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
state.remoteUid.value != ""
|
||||
state.remoteAssistantUid.value != ""
|
||||
? AgoraVideoView(
|
||||
controller: VideoViewController(
|
||||
rtcEngine: state.rctEngine.value!,
|
||||
|
|
@ -1592,7 +1720,8 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
Text(
|
||||
'主持人正在赶来的路上...',
|
||||
style: TextStyle(
|
||||
color: ColorUtil.Color_255_255_255, fontSize: 14.sp),
|
||||
color: ColorUtil.Color_255_255_255,
|
||||
fontSize: 14.sp),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
@ -1646,17 +1775,19 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
crossAxisCount: 2, childAspectRatio: 0.8, crossAxisSpacing: 0),
|
||||
itemCount: state.cacheUsers.value.length,
|
||||
itemBuilder: (BuildContext ctx, index) {
|
||||
return Stack(
|
||||
return GestureDetector(
|
||||
child: Stack(
|
||||
children: [
|
||||
state.cacheUsers.value[index].enableCamera == true
|
||||
? state.cacheUsers.value[index].uid == UserStore.to.userInfoEntity.value!.uid
|
||||
? state.cacheUsers.value[index].uid ==
|
||||
UserStore.to.userInfoEntity.value!.uid
|
||||
? AgoraVideoView(
|
||||
controller: VideoViewController(
|
||||
rtcEngine: state.rctEngine.value!,
|
||||
canvas: const VideoCanvas(
|
||||
uid: 0,
|
||||
setupMode:
|
||||
VideoViewSetupMode.videoViewSetupAdd)),
|
||||
setupMode: VideoViewSetupMode
|
||||
.videoViewSetupAdd)),
|
||||
)
|
||||
: AgoraVideoView(
|
||||
controller: VideoViewController.remote(
|
||||
|
|
@ -1714,7 +1845,8 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
color: ColorUtil.Color_0_0_0_96),
|
||||
child: state.cacheUsers.value[index].enableMicr == true
|
||||
child: state.cacheUsers.value[index].enableMicr ==
|
||||
true
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
|
|
@ -1738,14 +1870,15 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
SizedBox(
|
||||
width: 70,
|
||||
child: Text(
|
||||
state.cacheUsers.value[index].userName,
|
||||
state
|
||||
.cacheUsers.value[index].userName,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
color: ColorUtil.Color_255_255_255),
|
||||
)
|
||||
)
|
||||
color:
|
||||
ColorUtil.Color_255_255_255),
|
||||
))
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
|
|
@ -1760,14 +1893,15 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
SizedBox(
|
||||
width: 70,
|
||||
child: Text(
|
||||
state.cacheUsers.value[index].userName,
|
||||
state
|
||||
.cacheUsers.value[index].userName,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
color: ColorUtil.Color_255_255_255),
|
||||
)
|
||||
)
|
||||
color:
|
||||
ColorUtil.Color_255_255_255),
|
||||
))
|
||||
],
|
||||
),
|
||||
)
|
||||
|
|
@ -1775,6 +1909,14 @@ class MeetingMainPageState extends State<MeetingMainPage> {
|
|||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
onTap: (){
|
||||
if(state.cacheUsers.value[index].enableCamera == true){
|
||||
logic.checkLargeScreen(state.cacheUsers.value[index].uid);
|
||||
}else{
|
||||
ToastUtils.showError("该用户暂未开启摄像头");
|
||||
}
|
||||
},
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -57,11 +57,13 @@ class MeetingMainVoiceComponent extends StatelessWidget {
|
|||
),
|
||||
SizedBox(height: 6.h),
|
||||
users[index].enableMicr == true
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
? Text.rich(
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
TextSpan(
|
||||
children: [
|
||||
Container(
|
||||
WidgetSpan(
|
||||
child: Container(
|
||||
width: 20.w,
|
||||
height: 20.h,
|
||||
child: LiquidCustomProgressIndicator(
|
||||
|
|
@ -71,42 +73,42 @@ class MeetingMainVoiceComponent extends StatelessWidget {
|
|||
direction: Axis.vertical,
|
||||
shapePath: ViewSvgPath.getMicrpphonePath()
|
||||
),
|
||||
)
|
||||
),
|
||||
SizedBox(
|
||||
width: 70,
|
||||
child: Text(
|
||||
users[index].userName,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
TextSpan(
|
||||
text: users[index].userName,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
color: ColorUtil.Color_255_255_255),
|
||||
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
)
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
: Text.rich(
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
TextSpan(
|
||||
children: [
|
||||
Image.asset(
|
||||
WidgetSpan(
|
||||
child: Image.asset(
|
||||
'assets/images/meeting_main_microphone_open.png',
|
||||
width: 20.w,
|
||||
height: 20.h,
|
||||
)
|
||||
),
|
||||
SizedBox(
|
||||
width: 70,
|
||||
child: Text(
|
||||
users[index].userName,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
TextSpan(
|
||||
text: users[index].userName,
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
color: ColorUtil.Color_255_255_255),
|
||||
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
)
|
||||
],
|
||||
);
|
||||
})),
|
||||
|
|
|
|||
|
|
@ -7,10 +7,4 @@ import 'user_state.dart';
|
|||
|
||||
class UserLogic extends GetxController with RequestToolMixin {
|
||||
final UserState state = UserState();
|
||||
|
||||
/// 退出登录
|
||||
void logout(){
|
||||
UserStore.to.erase();
|
||||
Get.toNamed(Routes.loginPage);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ class UserPageState extends State<UserPage> {
|
|||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||
margin: const EdgeInsets.only(top: 20),
|
||||
margin: const EdgeInsets.only(top: 30),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@ class ColorUtil {
|
|||
|
||||
static const Color_255_69_69 = Color.fromRGBO(255, 69, 69, 1);
|
||||
|
||||
static const Color_84_84_84 = Color.fromRGBO(84, 84, 84, 1);
|
||||
|
||||
/// 十六进制颜色,
|
||||
/// hex, 十六进制值,例如:0xffffff,
|
||||
/// alpha, 透明度 [0.0,1.0]
|
||||
|
|
|
|||
|
|
@ -17,9 +17,16 @@ class AndroidPermissionHandler {
|
|||
await requestMicrophonePermission();
|
||||
}
|
||||
|
||||
Future<void> requestCameraToMicrophonePermissions() async {
|
||||
await requestCameraPermission();
|
||||
await requestMicrophonePermission();
|
||||
Future<bool> requestCameraToMicrophonePermissions() async {
|
||||
var isCameraPermission = false;
|
||||
var isMicrophonePermissio = false;
|
||||
if(await requestCameraPermission() == true){
|
||||
isCameraPermission = true;
|
||||
}
|
||||
if(await requestMicrophonePermission() == true){
|
||||
isMicrophonePermissio = true;
|
||||
}
|
||||
return isCameraPermission == true && isMicrophonePermissio == true;
|
||||
}
|
||||
|
||||
Future<void> requestLocationPermission() async {
|
||||
|
|
@ -58,10 +65,12 @@ class AndroidPermissionHandler {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> requestCameraPermission() async {
|
||||
Future<bool> requestCameraPermission() async {
|
||||
var isCameraPermission = false;
|
||||
PermissionStatus status = await Permission.camera.request();
|
||||
if (status.isGranted) {
|
||||
print("Android: 摄像头权限已授予");
|
||||
isCameraPermission = true;
|
||||
} else if (status.isPermanentlyDenied) {
|
||||
print("Android: 摄像头权限被永久拒绝,请前往设置开启");
|
||||
ToastUtils.showError("权限被永久拒绝,请前往设置开启!");
|
||||
|
|
@ -70,17 +79,21 @@ class AndroidPermissionHandler {
|
|||
print("Android: 摄像头权限被拒绝");
|
||||
ToastUtils.showError("权限被拒绝,可能会导致相关功能不可用!");
|
||||
}
|
||||
return isCameraPermission;
|
||||
}
|
||||
|
||||
Future<void> requestStoragePermission() async {
|
||||
PermissionStatus status = await Permission.storage.request();
|
||||
Future<bool> requestStoragePermission() async {
|
||||
var isStoragePermission = false;
|
||||
PermissionStatus status = await Permission.manageExternalStorage.request();
|
||||
if (status.isGranted) {
|
||||
print("Android: 存储权限已授予");
|
||||
isStoragePermission = true;
|
||||
} else if (status.isPermanentlyDenied) {
|
||||
print("Android: 存储权限被永久拒绝,请前往设置开启");
|
||||
} else {
|
||||
print("Android: 存储权限被拒绝");
|
||||
}
|
||||
return isStoragePermission;
|
||||
}
|
||||
|
||||
Future<void> requestNotificationPermission() async {
|
||||
|
|
@ -105,10 +118,12 @@ class AndroidPermissionHandler {
|
|||
}
|
||||
}
|
||||
|
||||
static Future<void> requestMicrophonePermission() async {
|
||||
static Future<bool> requestMicrophonePermission() async {
|
||||
var isMicrophonePermission = false;
|
||||
PermissionStatus status = await Permission.microphone.request();
|
||||
if (status.isGranted) {
|
||||
print("Android: 麦克风权限已授予");
|
||||
isMicrophonePermission = true;
|
||||
} else if (status.isPermanentlyDenied) {
|
||||
print("Android: 麦克风权限被永久拒绝,请前往设置开启");
|
||||
ToastUtils.showError("权限被永久拒绝,请前往设置开启!");
|
||||
|
|
@ -117,5 +132,6 @@ class AndroidPermissionHandler {
|
|||
print("Android: 麦克风限被拒绝");
|
||||
ToastUtils.showError("权限被拒绝,可能会导致相关功能不可用!");
|
||||
}
|
||||
return isMicrophonePermission;
|
||||
}
|
||||
}
|
||||
|
|
@ -13,9 +13,16 @@ class IosPermissionHandler {
|
|||
await requestMicrophonePermission();
|
||||
}
|
||||
|
||||
Future<void> requestCameraToMicrophonePermissions() async {
|
||||
await requestCameraPermission();
|
||||
await requestMicrophonePermission();
|
||||
Future<bool> requestCameraToMicrophonePermissions() async {
|
||||
var isCameraPermission = false;
|
||||
var isMicrophonePermissio = false;
|
||||
if(await requestCameraPermission() == true){
|
||||
isCameraPermission = true;
|
||||
}
|
||||
if(await requestMicrophonePermission() == true){
|
||||
isMicrophonePermissio = true;
|
||||
}
|
||||
return isCameraPermission == true && isMicrophonePermissio == true;
|
||||
}
|
||||
|
||||
Future<void> requestLocationPermission() async {
|
||||
|
|
@ -38,10 +45,12 @@ class IosPermissionHandler {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> requestCameraPermission() async {
|
||||
Future<bool> requestCameraPermission() async {
|
||||
var isCameraPermission = false;
|
||||
PermissionStatus status = await Permission.camera.request();
|
||||
if (status.isGranted) {
|
||||
print("iOS: 摄像头权限已授予");
|
||||
isCameraPermission = true;
|
||||
} else if (status.isPermanentlyDenied) {
|
||||
print("iOS: 摄像头权限被永久拒绝,请前往设置开启");
|
||||
ToastUtils.showError("权限被永久拒绝,请前往设置开启!");
|
||||
|
|
@ -50,17 +59,21 @@ class IosPermissionHandler {
|
|||
print("iOS: 摄像头权限被拒绝");
|
||||
ToastUtils.showError("权限被拒绝,可能会导致相关功能不可用!");
|
||||
}
|
||||
return isCameraPermission;
|
||||
}
|
||||
|
||||
Future<void> requestStoragePermission() async {
|
||||
Future<bool> requestStoragePermission() async {
|
||||
var isStoragePermission = false;
|
||||
PermissionStatus status = await Permission.photos.request();
|
||||
if (status.isGranted) {
|
||||
print("iOS: 存储权限已授予");
|
||||
isStoragePermission = true;
|
||||
} else if (status.isPermanentlyDenied) {
|
||||
print("iOS: 存储权限被永久拒绝,请前往设置开启");
|
||||
} else {
|
||||
print("iOS: 存储权限被拒绝");
|
||||
}
|
||||
return isStoragePermission;
|
||||
}
|
||||
|
||||
Future<void> requestNotificationPermission() async {
|
||||
|
|
@ -83,10 +96,12 @@ class IosPermissionHandler {
|
|||
}
|
||||
}
|
||||
|
||||
static Future<void> requestMicrophonePermission() async {
|
||||
static Future<bool> requestMicrophonePermission() async {
|
||||
var isMicrophonePermission = false;
|
||||
PermissionStatus status = await Permission.microphone.request();
|
||||
if (status.isGranted) {
|
||||
print("iOS: 麦克风权限已授予");
|
||||
isMicrophonePermission = true;
|
||||
} else if (status.isPermanentlyDenied) {
|
||||
print("iOS: 麦克风权限被永久拒绝,请前往设置开启");
|
||||
ToastUtils.showError("权限被永久拒绝,请前往设置开启!");
|
||||
|
|
@ -95,5 +110,6 @@ class IosPermissionHandler {
|
|||
print("iOS: 麦克风限被拒绝");
|
||||
ToastUtils.showError("权限被拒绝,可能会导致相关功能不可用!");
|
||||
}
|
||||
return isMicrophonePermission;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +1,47 @@
|
|||
import 'dart:io';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
import 'AndroidPermissionHandler.dart';
|
||||
import 'IosPermissionHandler.dart';
|
||||
|
||||
class PermissionService {
|
||||
static Future<void> requestPermissions() async {
|
||||
static Future<bool> requestPermissions() async {
|
||||
var isRequestPermissions = false;
|
||||
if (Platform.isIOS) {
|
||||
// 调用iOS权限处理逻辑
|
||||
await IosPermissionHandler().requestCameraToMicrophonePermissions();
|
||||
isRequestPermissions = await IosPermissionHandler().requestCameraToMicrophonePermissions();
|
||||
} else if (Platform.isAndroid) {
|
||||
// 调用Android权限处理逻辑
|
||||
await AndroidPermissionHandler().requestCameraToMicrophonePermissions();
|
||||
isRequestPermissions = await AndroidPermissionHandler().requestCameraToMicrophonePermissions();
|
||||
}
|
||||
return isRequestPermissions;
|
||||
}
|
||||
|
||||
static Future<bool> requestStoragePermissions() async {
|
||||
var isRequestPermissions = false;
|
||||
if (Platform.isIOS) {
|
||||
// 调用iOS权限处理逻辑
|
||||
isRequestPermissions = await IosPermissionHandler().requestStoragePermission();
|
||||
} else if (Platform.isAndroid) {
|
||||
// 调用Android权限处理逻辑
|
||||
isRequestPermissions = await AndroidPermissionHandler().requestStoragePermission();
|
||||
}
|
||||
return isRequestPermissions;
|
||||
}
|
||||
|
||||
/// 检测是否有权限
|
||||
static Future<bool> checkPermission({required List<Permission> permissionList}) async {
|
||||
var isRequestPermissions = true;
|
||||
///遍历当前权限申请列表
|
||||
for (Permission permission in permissionList) {
|
||||
PermissionStatus status = await permission.status;
|
||||
///如果有不允许状态
|
||||
if (!status.isGranted) {
|
||||
isRequestPermissions = false;
|
||||
}
|
||||
}
|
||||
return isRequestPermissions;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get/get_core/src/get_main.dart';
|
||||
|
||||
class RouteUtil {
|
||||
|
||||
/**
|
||||
* 获取当前路由
|
||||
*/
|
||||
static String getRoute(){
|
||||
var routePath = Get.currentRoute;
|
||||
return routePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取context
|
||||
*/
|
||||
static BuildContext getContext(){
|
||||
var context = Get.context!;
|
||||
return context;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_screenutil/src/size_extension.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get/get_core/src/get_main.dart';
|
||||
import 'package:install_plugin/install_plugin.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:wgshare/utils/color_util.dart';
|
||||
import 'package:wgshare/utils/toast_utils.dart';
|
||||
import 'package:wgshare/view/upgrade/util/load_file_cancel_request.dart';
|
||||
|
||||
publicDialog(BuildContext context,
|
||||
{String title = "提示",
|
||||
required String describe,
|
||||
btnWidth = 116.0,
|
||||
btnHeight = 42.0,
|
||||
required String leftBtnStr,
|
||||
required String rightBtnStr,
|
||||
bool hideCancelBtn = false,
|
||||
required Function leftBtnCallback,
|
||||
required Function rightBtnCallback}) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: hideCancelBtn,
|
||||
builder: (_) => PopScope(
|
||||
canPop: hideCancelBtn,
|
||||
child: HintDialog(title, describe, btnWidth, btnHeight, leftBtnStr,
|
||||
rightBtnStr, hideCancelBtn,leftBtnCallback,rightBtnCallback),
|
||||
));
|
||||
}
|
||||
|
||||
class HintDialog extends StatefulWidget {
|
||||
final String title; //标题
|
||||
final String describe; //描述
|
||||
final double btnWidth; //按钮宽度
|
||||
final double btnHeight; //按钮高度
|
||||
final String leftBtnStr; // 左侧按钮内容
|
||||
final String rightBtnStr; //右侧按钮内容
|
||||
final bool hideCancelBtn; //是否隐藏取消btn(实际用途为是否可以点击空白和返回键关闭)
|
||||
final Function leftBtnCallback;
|
||||
final Function rightBtnCallback;
|
||||
|
||||
HintDialog(
|
||||
this.title,
|
||||
this.describe,
|
||||
this.btnWidth,
|
||||
this.btnHeight,
|
||||
this.leftBtnStr,
|
||||
this.rightBtnStr,
|
||||
this.hideCancelBtn,
|
||||
this.leftBtnCallback,
|
||||
this.rightBtnCallback);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return HintDialogState();
|
||||
}
|
||||
}
|
||||
|
||||
class HintDialogState extends State<HintDialog> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Container(
|
||||
height: 250.h,
|
||||
margin: const EdgeInsets.only(left: 40, right: 40),
|
||||
padding:
|
||||
const EdgeInsets.only(top: 20, bottom: 20, left: 12, right: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color.fromRGBO(255, 255, 255, 1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: _contentStyle(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///内容区域样式
|
||||
_contentStyle() {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
_title(),
|
||||
Expanded(
|
||||
child: _hintMsg(),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
GestureDetector(
|
||||
child: Container(
|
||||
width: widget.btnWidth,
|
||||
height: widget.btnHeight,
|
||||
decoration: const BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(99)),
|
||||
color: ColorUtil.Color_230_230_230,
|
||||
),
|
||||
margin: const EdgeInsets.only(top: 12, left: 12),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
widget.leftBtnStr,
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp, color: ColorUtil.Color_255_255_255),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
Get.back();
|
||||
widget.leftBtnCallback();
|
||||
},
|
||||
),
|
||||
GestureDetector(
|
||||
child: Container(
|
||||
width: widget.btnWidth,
|
||||
height: widget.btnHeight,
|
||||
decoration: const BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(99)),
|
||||
color: ColorUtil.Color_85_117_242,
|
||||
),
|
||||
margin: const EdgeInsets.only(top: 12, right: 12),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
widget.rightBtnStr,
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp, color: ColorUtil.Color_255_255_255),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
Get.back();
|
||||
widget.rightBtnCallback();
|
||||
},
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
///提示标题布局
|
||||
_title() {
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
child: Text(widget.title,
|
||||
style: TextStyle(
|
||||
fontSize: 16.sp,
|
||||
color: ColorUtil.Color_85_117_242,
|
||||
fontWeight: FontWeight.w600,
|
||||
decoration: TextDecoration.none)),
|
||||
);
|
||||
}
|
||||
|
||||
///提示信息布局
|
||||
_hintMsg() {
|
||||
return SingleChildScrollView(
|
||||
child: Container(
|
||||
alignment: Alignment.topLeft,
|
||||
margin: const EdgeInsets.only(left: 8, right: 8),
|
||||
child: Text(widget.describe,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: ColorUtil.Color_89_88_88,
|
||||
decoration: TextDecoration.none,
|
||||
height: 1.4)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_screenutil/src/size_extension.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:install_plugin/install_plugin.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:wgshare/utils/color_util.dart';
|
||||
import 'package:wgshare/utils/toast_utils.dart';
|
||||
import 'package:wgshare/view/upgrade/util/load_file_cancel_request.dart';
|
||||
|
||||
import '../../common/store/business_store.dart';
|
||||
import '../../utils/permission/PermissionService.dart';
|
||||
import '../public_dialog.dart';
|
||||
|
||||
hideUpgradeDialog(
|
||||
BuildContext context,
|
||||
String describe,
|
||||
String apkSavePath,
|
||||
String appStoreUrl,
|
||||
int versionCode,{
|
||||
btnWidth = 116.0,
|
||||
btnHeight = 42.0,
|
||||
bool hideCancelBtn = false,
|
||||
}) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: hideCancelBtn,
|
||||
builder: (_) => PopScope(
|
||||
canPop: hideCancelBtn,
|
||||
child: HintDialog(describe, apkSavePath, appStoreUrl, versionCode, btnWidth,
|
||||
btnHeight, hideCancelBtn),
|
||||
));
|
||||
}
|
||||
|
||||
class HintDialog extends StatefulWidget {
|
||||
final String describe; //版本更新内容
|
||||
final String apkSavePath;
|
||||
final String appStoreUrl;
|
||||
final int versionCode;
|
||||
final double btnWidth; //按钮宽度
|
||||
final double btnHeight; //按钮高度
|
||||
final bool hideCancelBtn; //是否隐藏取消btn(实际用途还是否可以点击空白和返回键关闭)
|
||||
|
||||
HintDialog(this.describe, this.apkSavePath, this.appStoreUrl, this.versionCode, this.btnWidth,
|
||||
this.btnHeight, this.hideCancelBtn);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return HintDialogState();
|
||||
}
|
||||
}
|
||||
|
||||
class HintDialogState extends State<HintDialog> {
|
||||
// 安装按钮状态,0:未点击、1:安装成功、2:安装失败
|
||||
int confirmBtnType = 0;
|
||||
|
||||
// 按钮文字
|
||||
String btnStr = "立即安装";
|
||||
|
||||
// apk路径
|
||||
late String apkPath;
|
||||
|
||||
late loadFileCancelRequest loadRequest;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Container(
|
||||
height: 400.h,
|
||||
margin: const EdgeInsets.only(left: 40, right: 40),
|
||||
padding:
|
||||
const EdgeInsets.only(top: 20, bottom: 20, left: 12, right: 12),
|
||||
decoration: const BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage('assets/images/upappbg.png'),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
child: _contentStyle(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///内容区域样式
|
||||
_contentStyle() {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
// _title(),
|
||||
Expanded(
|
||||
child: Container(),
|
||||
),
|
||||
_hintMsg(),
|
||||
GestureDetector(
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 50.h,
|
||||
decoration: const BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(6)),
|
||||
color: ColorUtil.Color_85_117_242,
|
||||
),
|
||||
margin: const EdgeInsets.only(top: 12),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
btnStr,
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp, color: ColorUtil.Color_255_255_255),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
if (Platform.isIOS) {
|
||||
_gotoAppStore();
|
||||
} else {
|
||||
if (confirmBtnType == 0) {
|
||||
PermissionService.checkPermission(permissionList: [Permission.manageExternalStorage]).then((value){
|
||||
if(value == true){
|
||||
_installApk();
|
||||
}else{
|
||||
publicDialog(Get.context!,
|
||||
hideCancelBtn: true,
|
||||
title: '请求权限说明',
|
||||
describe:
|
||||
'APP需要获取您的文件访问权限,用以确保新版本下载后可以正常安装。',
|
||||
leftBtnStr: '拒绝',
|
||||
rightBtnStr: '同意',
|
||||
leftBtnCallback: () {
|
||||
BusinessStore.to.setIsRefuseHomeCheckPermission(true);
|
||||
}, rightBtnCallback: () {
|
||||
PermissionService.requestStoragePermissions().then((value){
|
||||
if(value == true){
|
||||
_installApk();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
/*if (confirmBtnType == 1) {
|
||||
SystemNavigator.pop();
|
||||
}
|
||||
if (confirmBtnType == 2) {
|
||||
Navigator.of(context).pop();
|
||||
}*/
|
||||
}
|
||||
},
|
||||
),
|
||||
Visibility(
|
||||
visible: widget.hideCancelBtn,
|
||||
child: GestureDetector(
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(top: 20),
|
||||
child: Text(
|
||||
"跳过此版本",
|
||||
style:
|
||||
TextStyle(fontSize: 14.sp, color: ColorUtil.Color_84_84_84),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
BusinessStore.to.setSkipUpVersion(widget.versionCode);
|
||||
Get.back();
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
///提示信息布局
|
||||
_hintMsg() {
|
||||
return SingleChildScrollView(
|
||||
child: Container(
|
||||
alignment: Alignment.topLeft,
|
||||
margin: const EdgeInsets.only(),
|
||||
child: Text(widget.describe,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: ColorUtil.Color_244_244_244,
|
||||
decoration: TextDecoration.none,
|
||||
height: 1.4)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 安装APK
|
||||
_installApk() async {
|
||||
await InstallPlugin.installApk(widget.apkSavePath, appId: "com.yuanxuan.wgshare").then((result) {
|
||||
debugPrint("检查更新-安卓安装成功:$result");
|
||||
/*setState(() {
|
||||
confirmBtnType = 2;
|
||||
btnStr = "关闭APP,重新打开";
|
||||
});*/
|
||||
BusinessStore.to.erase();
|
||||
}).catchError((error) {
|
||||
debugPrint("检查更新-安卓安装失败:$error");
|
||||
/*setState(() {
|
||||
confirmBtnType = 2;
|
||||
btnStr = "跳过";
|
||||
});*/
|
||||
});
|
||||
}
|
||||
|
||||
/// 跳转苹果应用商店
|
||||
_gotoAppStore() async {
|
||||
await InstallPlugin.install(widget.appStoreUrl).then((result) {
|
||||
debugPrint("检查更新-苹果安装成功:$result");
|
||||
}).catchError((error) {
|
||||
debugPrint("检查更新-苹果安装失败:$error");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'upgrade_entity.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class UpgradeEntity extends Object {
|
||||
|
||||
@JsonKey(name: 'code')
|
||||
int code;
|
||||
|
||||
@JsonKey(name: 'message')
|
||||
String message;
|
||||
|
||||
@JsonKey(name: 'success')
|
||||
bool success;
|
||||
|
||||
@JsonKey(name: 'data')
|
||||
UpgradeData data;
|
||||
|
||||
UpgradeEntity(this.code,this.message,this.success,this.data,);
|
||||
|
||||
factory UpgradeEntity.fromJson(Map<String, dynamic> srcJson) => _$UpgradeEntityFromJson(srcJson);
|
||||
|
||||
Map<String, dynamic> toJson() => _$UpgradeEntityToJson(this);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class UpgradeData extends Object {
|
||||
|
||||
@JsonKey(name: 'versionCode')
|
||||
int versionCode;
|
||||
|
||||
@JsonKey(name: 'versionName')
|
||||
String versionName;
|
||||
|
||||
@JsonKey(name: 'updateType')
|
||||
int updateType;
|
||||
|
||||
@JsonKey(name: 'versionDescribe')
|
||||
String versionDescribe;
|
||||
|
||||
@JsonKey(name: 'androidurl')
|
||||
String androidurl;
|
||||
|
||||
@JsonKey(name: 'appStoreUrl')
|
||||
String appStoreUrl;
|
||||
|
||||
UpgradeData(this.versionCode,this.versionName,this.updateType,this.versionDescribe,this.androidurl,this.appStoreUrl);
|
||||
|
||||
factory UpgradeData.fromJson(Map<String, dynamic> srcJson) => _$UpgradeDataFromJson(srcJson);
|
||||
|
||||
Map<String, dynamic> toJson() => _$UpgradeDataToJson(this);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:al_downloader/al_downloader.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:wgshare/utils/toast_utils.dart';
|
||||
import 'package:wgshare/view/upgrade/hide_upgrade_dialog.dart';
|
||||
import '../../../common/models/app_updata_info_entity.dart';
|
||||
import '../../../common/store/business_store.dart';
|
||||
import '../../../utils/routeUtil.dart';
|
||||
import 'entity/upgrade_entity.dart';
|
||||
|
||||
class HideCheckVersion{
|
||||
Future<Map> request(String url) async{
|
||||
Response response = await Dio().get(url);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
Future<void> doHttpHideCheckVersion() async {
|
||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
String versionCode = packageInfo.buildNumber;
|
||||
|
||||
if(null != BusinessStore.to.appUpdataInfoEntity.value){
|
||||
ToastUtils.showSuccess('00000');
|
||||
if(int.tryParse(versionCode)! < BusinessStore.to.appUpdataInfoEntity.value!.versionCode){
|
||||
ToastUtils.showSuccess('11111--缓存跳过版本${BusinessStore.to.skipUpVersion}-缓存安装版本${BusinessStore.to.appUpdataInfoEntity.value!.versionCode}');
|
||||
if(null != BusinessStore.to.skipUpVersion){
|
||||
if(BusinessStore.to.skipUpVersion! < BusinessStore.to.appUpdataInfoEntity.value!.versionCode){
|
||||
hideUpgradeDialog(
|
||||
RouteUtil.getContext(),
|
||||
BusinessStore.to.appUpdataInfoEntity.value!.versionDescribe,
|
||||
hideCancelBtn: BusinessStore.to.appUpdataInfoEntity.value!.updateType == 1 ? false : true,
|
||||
BusinessStore.to.appUpdataInfoEntity.value!.apkSavePath,
|
||||
BusinessStore.to.appUpdataInfoEntity.value!.appStoreUrl,
|
||||
BusinessStore.to.appUpdataInfoEntity.value!.versionCode,
|
||||
);
|
||||
}else{
|
||||
ToastUtils.showSuccess('22222');
|
||||
doHttpUp();
|
||||
}
|
||||
}else{
|
||||
doHttpUp();
|
||||
}
|
||||
}else{
|
||||
ToastUtils.showSuccess('33333');
|
||||
BusinessStore.to.erase();
|
||||
}
|
||||
}else{
|
||||
ToastUtils.showSuccess('44444');
|
||||
doHttpUp();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> doHttpUp() async {
|
||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
String versionCode = packageInfo.buildNumber;
|
||||
|
||||
Future<Map> map = request("http://192.168.2.9:8827/latest.json");
|
||||
map.then((result) async {
|
||||
var jsonStr = json.encode(result);
|
||||
var listDynamic = jsonDecode(jsonStr);
|
||||
UpgradeEntity upgradeEntity = UpgradeEntity.fromJson(listDynamic);
|
||||
|
||||
debugPrint('55555${upgradeEntity.code}-${upgradeEntity.data.versionCode}-${upgradeEntity.data.androidurl}');
|
||||
ToastUtils.showSuccess('55555${upgradeEntity.code}-${upgradeEntity.data.versionCode}-${upgradeEntity.data.androidurl}');
|
||||
|
||||
if(upgradeEntity.code == 200){
|
||||
|
||||
debugPrint("检查更新-服务器版本信息:$jsonStr");
|
||||
debugPrint("检查更新-当前版本号:$versionCode");
|
||||
|
||||
if(int.tryParse(versionCode)! < upgradeEntity.data.versionCode){
|
||||
if((BusinessStore.to.skipUpVersion ?? 0) < upgradeEntity.data.versionCode){
|
||||
if (Platform.isAndroid) {
|
||||
/// 下载APK
|
||||
try {
|
||||
var appDocDir = await getTemporaryDirectory();
|
||||
var apkSavePath = "${appDocDir.path}/wgshare_up.apk";
|
||||
// String url = "https://www.onlinedown.net/iopdfbhjl/632869?module=download&t=website&v=20241229163449";
|
||||
// String url = "https://s3.cn-north-1.amazonaws.com.cn/mtab.kezaihui.com/apk/takeaway_phone_release_1.apk";
|
||||
String url = upgradeEntity.data.androidurl;
|
||||
ALDownloader.download(url,
|
||||
directoryPath: "${appDocDir.path}/",
|
||||
fileName: "wgshare_up.apk",
|
||||
handlerInterface:
|
||||
ALDownloaderHandlerInterface(progressHandler: (progress) {
|
||||
debugPrint('检查更新 | 下载进度 = $progress, url = $url');
|
||||
ToastUtils.showSuccess('下载进度$progress');
|
||||
}, succeededHandler: () {
|
||||
debugPrint('检查更新 | 下载成功, url = $url');
|
||||
debugPrint('检查更新,当前路由是:${RouteUtil.getRoute()}');
|
||||
debugPrint('检查更新,APK保存路径:$apkSavePath');
|
||||
|
||||
BusinessStore.to.setAppUpdataInfo(AppUpdataInfoEntity(
|
||||
upgradeEntity.data.versionCode,
|
||||
upgradeEntity.data.versionName,
|
||||
upgradeEntity.data.updateType,
|
||||
upgradeEntity.data.versionDescribe,
|
||||
upgradeEntity.data.androidurl,
|
||||
upgradeEntity.data.appStoreUrl,
|
||||
apkSavePath
|
||||
));
|
||||
|
||||
if (RouteUtil.getRoute() == '/meetingMainPage') {
|
||||
ToastUtils.showInfo(
|
||||
"新版本静默下载完毕\n将择机通知安装",
|
||||
duration: const Duration(milliseconds: 3000));
|
||||
} else {
|
||||
hideUpgradeDialog(
|
||||
RouteUtil.getContext(),
|
||||
upgradeEntity.data.versionDescribe,
|
||||
hideCancelBtn: upgradeEntity.data.updateType == 1 ? false : true,
|
||||
apkSavePath,
|
||||
'',
|
||||
upgradeEntity.data.versionCode,
|
||||
);
|
||||
}
|
||||
}, failedHandler: () {
|
||||
debugPrint('检查更新 | 下载失败, url = $url');
|
||||
}, pausedHandler: () {
|
||||
debugPrint('检查更新 | 下载暂停, url = $url');
|
||||
}));
|
||||
} catch (e) {
|
||||
debugPrint("检查更新-安卓下载失败:$e");
|
||||
}
|
||||
}else{
|
||||
hideUpgradeDialog(
|
||||
RouteUtil.getContext(),
|
||||
upgradeEntity.data.versionDescribe,
|
||||
hideCancelBtn: upgradeEntity.data.updateType == 1 ? false : true,
|
||||
'',
|
||||
upgradeEntity.data.appStoreUrl,
|
||||
upgradeEntity.data.versionCode,
|
||||
);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import '../upgrade_dialog.dart';
|
||||
import 'entity/upgrade_entity.dart';
|
||||
|
||||
Future<Map> request(String url) async{
|
||||
Response response = await Dio().get(url);
|
||||
return response.data;
|
||||
}
|
||||
void doHttpCheckVersion(BuildContext context){
|
||||
Future<Map> map = request("https://meeting-api.23544.com/meeting/mobile/latest.json");
|
||||
map.then((result) async {
|
||||
var jsonStr = json.encode(result);
|
||||
var listDynamic = jsonDecode(jsonStr);
|
||||
UpgradeEntity upgradeEntity = UpgradeEntity.fromJson(listDynamic);
|
||||
|
||||
if(upgradeEntity.code == 200){
|
||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
String versionCode = packageInfo.buildNumber;
|
||||
if(int.tryParse(versionCode)! < 2){
|
||||
debugPrint("检查更新-服务器版本信息:$jsonStr");
|
||||
debugPrint("检查更新-当前版本号:$versionCode");
|
||||
upgradeDialog(
|
||||
context,
|
||||
upgradeEntity.data.versionDescribe,
|
||||
hideCancelBtn: /*upgradeEntity.data.updateType == 1 ? false : true*/true,
|
||||
title: '版本更新 v${upgradeEntity.data.versionName}',
|
||||
/*upgradeEntity.data.url*/'https://s3.cn-north-1.amazonaws.com.cn/mtab.kezaihui.com/apk/takeaway_phone_release_1.apk',
|
||||
upgradeEntity.data.appStoreUrl,
|
||||
upgradeEntity.data.versionName
|
||||
);
|
||||
}else{
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,290 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_screenutil/src/size_extension.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:install_plugin/install_plugin.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:wgshare/utils/color_util.dart';
|
||||
import 'package:wgshare/utils/toast_utils.dart';
|
||||
import 'package:wgshare/view/upgrade/util/load_file_cancel_request.dart';
|
||||
|
||||
import '../../utils/permission/PermissionService.dart';
|
||||
import '../public_dialog.dart';
|
||||
|
||||
upgradeDialog(
|
||||
BuildContext context,
|
||||
String describe,
|
||||
String url,
|
||||
String appStoreUrl,
|
||||
String versionName, {
|
||||
String title = "提示",
|
||||
btnWidth = 116.0,
|
||||
btnHeight = 42.0,
|
||||
bool hideCancelBtn = false,
|
||||
}) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: hideCancelBtn,
|
||||
builder: (_) => PopScope(
|
||||
canPop: hideCancelBtn,
|
||||
child: HintDialog(title, describe, url, appStoreUrl, versionName,
|
||||
btnWidth, btnHeight, hideCancelBtn),
|
||||
));
|
||||
}
|
||||
|
||||
class HintDialog extends StatefulWidget {
|
||||
final String title; //标题
|
||||
final String describe; //版本更新内容
|
||||
final String url;
|
||||
final String appStoreUrl;
|
||||
final String versionName;
|
||||
final double btnWidth; //按钮宽度
|
||||
final double btnHeight; //按钮高度
|
||||
final bool hideCancelBtn; //是否隐藏取消btn(实际用途还是否可以点击空白和返回键关闭)
|
||||
|
||||
HintDialog(this.title, this.describe, this.url, this.appStoreUrl,
|
||||
this.versionName, this.btnWidth, this.btnHeight, this.hideCancelBtn);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return HintDialogState();
|
||||
}
|
||||
}
|
||||
|
||||
class HintDialogState extends State<HintDialog> {
|
||||
// 安装按钮状态,0:未点击、1:点击下载、2:下载成功、3:安装成功、4:安装失败
|
||||
int confirmBtnType = 0;
|
||||
|
||||
// 按钮文字
|
||||
String btnStr = "立即更新";
|
||||
|
||||
// 下载进度
|
||||
double progressValue = 0.0;
|
||||
|
||||
// apk路径
|
||||
late String apkPath;
|
||||
|
||||
late loadFileCancelRequest loadRequest;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Container(
|
||||
height: 400.h,
|
||||
margin: const EdgeInsets.only(left: 40, right: 40),
|
||||
padding:
|
||||
const EdgeInsets.only(top: 20, bottom: 20, left: 12, right: 12),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage('assets/images/upappbg.png'),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
child: _contentStyle(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///内容区域样式
|
||||
_contentStyle() {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
// _title(),
|
||||
Expanded(
|
||||
child: Container(),
|
||||
),
|
||||
_hintMsg(),
|
||||
Visibility(
|
||||
visible: confirmBtnType == 1 ? true : false,
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 4.h,
|
||||
color: ColorUtil.Color_85_117_242,
|
||||
margin: const EdgeInsets.only(top: 12, left: 2, right: 2),
|
||||
child: LinearProgressIndicator(
|
||||
value: progressValue,
|
||||
valueColor:
|
||||
const AlwaysStoppedAnimation(ColorUtil.Color_85_117_242),
|
||||
backgroundColor: ColorUtil.Color_185_184_184,
|
||||
),
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 50.h,
|
||||
decoration: const BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(6)),
|
||||
color: ColorUtil.Color_85_117_242,
|
||||
),
|
||||
margin: const EdgeInsets.only(top: 12),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
btnStr,
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp, color: ColorUtil.Color_255_255_255),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
if (Platform.isIOS) {
|
||||
_gotoAppStore();
|
||||
} else {
|
||||
if (confirmBtnType == 0) {
|
||||
_downloadApk();
|
||||
}
|
||||
if (confirmBtnType == 1) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
if (confirmBtnType == 2) {
|
||||
PermissionService.checkPermission(permissionList: [Permission.manageExternalStorage]).then((value){
|
||||
if(value == true){
|
||||
// 下载完成,调用安装APK函数
|
||||
_installApk(apkPath);
|
||||
}else{
|
||||
publicDialog(context,
|
||||
hideCancelBtn: true,
|
||||
title: '请求权限说明',
|
||||
describe:
|
||||
'APP需要获取您的文件访问权限,用以确保新版本下载后可以正常安装。',
|
||||
leftBtnStr: '拒绝',
|
||||
rightBtnStr: '同意',
|
||||
leftBtnCallback: () {
|
||||
}, rightBtnCallback: () {
|
||||
PermissionService.requestStoragePermissions();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (confirmBtnType == 3) {
|
||||
SystemNavigator.pop();
|
||||
}
|
||||
if (confirmBtnType == 4) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
Visibility(
|
||||
visible: widget.hideCancelBtn,
|
||||
child: GestureDetector(
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(top: 20),
|
||||
child: Text(
|
||||
"跳过此版本",
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp,
|
||||
color: ColorUtil.Color_84_84_84
|
||||
),
|
||||
),
|
||||
),
|
||||
onTap: (){
|
||||
Get.back();
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
///提示标题布局
|
||||
_title() {
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
child: Text(widget.title,
|
||||
style: TextStyle(
|
||||
fontSize: 16.sp,
|
||||
color: ColorUtil.Color_85_117_242,
|
||||
fontWeight: FontWeight.w600,
|
||||
decoration: TextDecoration.none)),
|
||||
);
|
||||
}
|
||||
|
||||
///提示信息布局
|
||||
_hintMsg() {
|
||||
return SingleChildScrollView(
|
||||
child: Container(
|
||||
alignment: Alignment.topLeft,
|
||||
margin: const EdgeInsets.only(),
|
||||
child: Text(widget.describe,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: ColorUtil.Color_244_244_244,
|
||||
decoration: TextDecoration.none,
|
||||
height: 1.4)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 下载APK
|
||||
_downloadApk() async {
|
||||
loadRequest = loadFileCancelRequest();
|
||||
try {
|
||||
// 设置apk下载路径
|
||||
var appDocDir = await getTemporaryDirectory();
|
||||
apkPath = "${appDocDir.path}/wgshare_${widget.versionName}.apk";
|
||||
|
||||
loadRequest.load(widget.url, apkPath);
|
||||
|
||||
loadRequest.setProgressCallbackListener((progress) {
|
||||
setState(() {
|
||||
progressValue = progress;
|
||||
});
|
||||
});
|
||||
|
||||
loadRequest.setSuccessCallbackListener(() {
|
||||
setState(() {
|
||||
confirmBtnType = 2;
|
||||
btnStr = "安装";
|
||||
});
|
||||
});
|
||||
|
||||
setState(() {
|
||||
confirmBtnType = 1;
|
||||
btnStr = "取消";
|
||||
});
|
||||
} catch (e) {
|
||||
debugPrint("检查更新-安卓下载失败:$e");
|
||||
setState(() {
|
||||
confirmBtnType = 0;
|
||||
btnStr = "更新";
|
||||
});
|
||||
ToastUtils.showError("下载失败");
|
||||
}
|
||||
}
|
||||
|
||||
/// 安装APK
|
||||
_installApk(String path) async {
|
||||
await InstallPlugin.installApk(path, appId: "com.yuanxuan.wgshare").then((result) {
|
||||
debugPrint("检查更新-安卓安装成功:$result");
|
||||
setState(() {
|
||||
confirmBtnType = 3;
|
||||
btnStr = "关闭APP,重新打开";
|
||||
});
|
||||
}).catchError((error) {
|
||||
debugPrint("检查更新-安卓安装失败:$error");
|
||||
setState(() {
|
||||
confirmBtnType = 4;
|
||||
btnStr = "跳过";
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// 跳转苹果应用商店
|
||||
_gotoAppStore() async {
|
||||
await InstallPlugin.install(widget.appStoreUrl).then((result){
|
||||
debugPrint("检查更新-苹果安装成功:$result");
|
||||
}).catchError((error){
|
||||
debugPrint("检查更新-苹果安装失败:$error");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class loadFileCancelRequest{
|
||||
|
||||
late Function progressCallback;
|
||||
late Function successCallback;
|
||||
|
||||
CancelToken token = CancelToken();
|
||||
|
||||
load(String url, String path) async {
|
||||
Dio dio = Dio();
|
||||
await dio.download(url, path, cancelToken: token, onReceiveProgress: (received, total) {
|
||||
if (total != -1) {
|
||||
// 下载进度
|
||||
progressCallback((received / total));
|
||||
debugPrint("检查更新-下载进度:${(received / total)}");
|
||||
}
|
||||
}).then((onValue){
|
||||
// 下载成功
|
||||
successCallback();
|
||||
});
|
||||
}
|
||||
|
||||
cancel() {
|
||||
token.cancel('取消请求');
|
||||
}
|
||||
|
||||
setProgressCallbackListener(Function progressCallback){
|
||||
this.progressCallback = progressCallback;
|
||||
}
|
||||
|
||||
setSuccessCallbackListener(Function successCallback){
|
||||
this.successCallback = successCallback;
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@ import macos_window_utils
|
|||
import package_info_plus
|
||||
import path_provider_foundation
|
||||
import sqflite_darwin
|
||||
import wakelock_plus
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
AgoraRtcNgPlugin.register(with: registry.registrar(forPlugin: "AgoraRtcNgPlugin"))
|
||||
|
|
@ -31,4 +32,5 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||
WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,14 @@ packages:
|
|||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "6.5.0"
|
||||
al_downloader:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: al_downloader
|
||||
sha256: "00b96b113da7e013f532527238e2f8e5219834f6b4e52df6ff8b12f26eda7101"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.8.4"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -246,6 +254,14 @@ packages:
|
|||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.0.9"
|
||||
dbus:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dbus
|
||||
sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.7.10"
|
||||
device_info_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -347,6 +363,14 @@ packages:
|
|||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.3.1"
|
||||
flutter_downloader:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_downloader
|
||||
sha256: "2b126083d2e6b7c09755bca12012c4c734bcf7666cf07ba00c508fcb83e8d0d7"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.11.1"
|
||||
flutter_easyloading:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -634,6 +658,14 @@ packages:
|
|||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
install_plugin:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: install_plugin
|
||||
sha256: "6fb67ba0781e75de4f2f2266ed25e835bfd277c5bfc2ed034af52774355857c6"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
intersperse:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -670,10 +702,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
|
||||
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.7.1"
|
||||
version: "0.6.7"
|
||||
json_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -843,7 +875,7 @@ packages:
|
|||
source: hosted
|
||||
version: "1.9.0"
|
||||
path_provider:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
|
||||
|
|
@ -938,6 +970,14 @@ packages:
|
|||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.2.1"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: petitparser
|
||||
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "6.0.2"
|
||||
photo_view:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -1010,6 +1050,14 @@ packages:
|
|||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
queue:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: queue
|
||||
sha256: "9a41ecadc15db79010108c06eae229a45c56b18db699760f34e8c9ac9b831ff9"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.1.0+2"
|
||||
retrofit:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -1263,6 +1311,22 @@ packages:
|
|||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "14.2.5"
|
||||
wakelock_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: wakelock_plus
|
||||
sha256: "36c88af0b930121941345306d259ec4cc4ecca3b151c02e3a9e71aede83c615e"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.2.10"
|
||||
wakelock_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: wakelock_plus_platform_interface
|
||||
sha256: "70e780bc99796e1db82fe764b1e7dcb89a86f1e5b3afb1db354de50f2e41eb7a"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.2.2"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -1311,6 +1375,14 @@ packages:
|
|||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
xml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xml
|
||||
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "6.5.0"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -92,6 +92,18 @@ dependencies:
|
|||
# 弹窗
|
||||
adaptive_dialog: ^2.3.0
|
||||
|
||||
# 安装apk
|
||||
install_plugin: ^2.1.0
|
||||
|
||||
# 文件目录
|
||||
path_provider: ^2.0.2
|
||||
|
||||
# 后台下载
|
||||
al_downloader: ^1.8.2
|
||||
|
||||
# 屏幕常亮
|
||||
wakelock_plus: ^1.2.10
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
|
|
|||