-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathairship_embedded_view.dart
More file actions
177 lines (155 loc) · 5.68 KB
/
airship_embedded_view.dart
File metadata and controls
177 lines (155 loc) · 5.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
import 'package:airship_flutter/airship_flutter.dart';
/// Embedded platform view.
///
/// Note: When an embedded view is set to display with its height set to `auto`
/// the embedded view will size to its native aspect ratio. Any remaining space
/// in the parent view will be apparent.
class AirshipEmbeddedView extends StatefulWidget {
/// The embedded view Id.
final String embeddedId;
/// Optional parent width. If not provided, the widget will use available width.
final double? parentWidth;
/// Optional parent height. If not provided, the widget will use available height.
/// Use parentHeight for constant height instead of a height-constrained container.
/// This allows proper collapse to 0 height when the view is dismissed.
final double? parentHeight;
/// A flag to use flutter hybrid composition method or not. Default to false.
static bool hybridComposition = false;
AirshipEmbeddedView({
required this.embeddedId,
this.parentWidth,
this.parentHeight,
});
@override
AirshipEmbeddedViewState createState() => AirshipEmbeddedViewState();
}
class AirshipEmbeddedViewState extends State<AirshipEmbeddedView>
with AutomaticKeepAliveClientMixin<AirshipEmbeddedView> {
late MethodChannel _channel;
late Stream<bool> _readyStream;
late final StreamSubscription<bool> _readySubscription;
bool? _isEmbeddedAvailable;
@override
void initState() {
super.initState();
// Get seed value once
_isEmbeddedAvailable =
Airship.inApp.isEmbeddedAvailable(embeddedId: widget.embeddedId);
// Then listen for changes
_readyStream =
Airship.inApp.isEmbeddedAvailableStream(embeddedId: widget.embeddedId);
_readySubscription = _readyStream.listen((v) {
if (mounted && v != _isEmbeddedAvailable) {
setState(() => _isEmbeddedAvailable = v);
}
});
}
Future<void> _methodCallHandler(MethodCall call) async {
switch (call.method) {
default:
print('Unknown method.');
}
}
Future<void> _onPlatformViewCreated(int id) async {
_channel = MethodChannel('com.airship.flutter/EmbeddedView_$id');
_channel.setMethodCallHandler(_methodCallHandler);
}
Widget buildReadyView(BuildContext context, Widget view, Size availableSize) {
return AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
transitionBuilder: (Widget child, Animation<double> animation) {
return FadeTransition(opacity: animation, child: child);
},
child: _isEmbeddedAvailable == true
? SizedBox(
key: ValueKey<bool>(true),
width: widget.parentWidth ?? availableSize.width,
height: widget.parentHeight ?? availableSize.height,
child: view,
)
: SizedBox(key: ValueKey<bool>(false), height: 0),
);
}
Widget wrapWithLayoutBuilder(Widget view) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final availableSize = MediaQuery.of(context).size;
return Center(child: buildReadyView(context, view, availableSize));
},
);
}
@override
Widget build(BuildContext context) {
super.build(context);
if (defaultTargetPlatform == TargetPlatform.android) {
return _getAndroidView();
} else if (defaultTargetPlatform == TargetPlatform.iOS) {
return wrapWithLayoutBuilder(
UiKitView(
viewType: 'com.airship.flutter/EmbeddedView',
onPlatformViewCreated: _onPlatformViewCreated,
creationParams: <String, Object?>{
'embeddedId': widget.embeddedId,
},
creationParamsCodec: const StandardMessageCodec(),
),
);
}
return Text('$defaultTargetPlatform is not yet supported by this plugin');
}
Widget _getAndroidView() {
if (AirshipEmbeddedView.hybridComposition) {
return wrapWithLayoutBuilder(PlatformViewLink(
viewType: 'com.airship.flutter/EmbeddedView',
surfaceFactory:
(BuildContext context, PlatformViewController controller) {
return AndroidViewSurface(
controller: controller as AndroidViewController,
gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{},
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
);
},
onCreatePlatformView: (PlatformViewCreationParams params) {
return PlatformViewsService.initSurfaceAndroidView(
id: params.id,
viewType: 'com.airship.flutter/EmbeddedView',
layoutDirection: TextDirection.ltr,
creationParams: <String, Object?>{
'embeddedId': widget.embeddedId,
},
creationParamsCodec: const StandardMessageCodec(),
onFocus: () {
params.onFocusChanged(true);
},
)
..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
..create();
},
));
} else {
return wrapWithLayoutBuilder(AndroidView(
viewType: 'com.airship.flutter/EmbeddedView',
onPlatformViewCreated: _onPlatformViewCreated,
creationParams: <String, Object?>{
'embeddedId': widget.embeddedId,
},
creationParamsCodec: const StandardMessageCodec(),
));
}
}
@override
void dispose() {
_readySubscription.cancel();
_channel.setMethodCallHandler(null);
super.dispose();
}
@override
bool get wantKeepAlive => true;
}