diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 6fa786f5..e962185d 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,9 +1,20 @@ - + + android:icon="@mipmap/ic_launcher" + android:allowBackup="false"> + + + + + + { GlobalKey sampleInputKey = GlobalKey(); GlobalKey sampleOutputKey = GlobalKey(); GlobalKey popUpKey = GlobalKey(); + final WebMetaTagUpdate metaTagUpdate = WebMetaTagUpdate(); late _SampleInputContainer inputContainer; late _SampleOutputContainer outputContainer; @@ -108,6 +109,10 @@ class _WebLayoutPageState extends State { model.addListener(_handleChange); super.initState(); + + // Updates meta tag details when navigating from the home page + // to a widget sample page. + metaTagUpdate.update(sample.title!, sample.control!.title!); } ///Notify the framework by calling this method @@ -573,6 +578,14 @@ class _SampleInputContainerState extends State<_SampleInputContainer> { widget.webLayoutPageState!.sample = item.subItems != null ? item.subItems![0] as SubItem : item; + + // Updates meta tag details when selecting a sample from the + // left panel in a widget page. + metaTagUpdate.update( + outputContainerState.sample.title!, + outputContainerState.sample.control!.title!, + ); + if (model.currentSampleKey == null || (item.key != null ? model.currentSampleKey != item.key @@ -751,6 +764,14 @@ class _SampleInputContainerState extends State<_SampleInputContainer> { list[i].title!; widget.webLayoutPageState!.selectSample = list[i].title; resetLocaleValue(model, outputContainerState.sample); + + // Updates meta tag details when selecting a sample from + // the left panel in a widget page. + metaTagUpdate.update( + outputContainerState.sample.title!, + outputContainerState.sample.control!.title!, + ); + if (model.currentSampleKey == null || (list[i].key != null ? model.currentSampleKey != list[i].key @@ -884,6 +905,10 @@ class _SampleInputContainerState extends State<_SampleInputContainer> { if (MediaQuery.of(context).size.width <= 768) { Navigator.pop(context); } + + // Sets default meta tag details when navigating back from a sample + // page to the home page. + metaTagUpdate.setDefault(); } } @@ -1844,6 +1869,13 @@ class SampleOutputContainerState extends State<_SampleOutputContainer> { outputContainerState.needTabs = true; outputContainerState.subItems = subItems; outputContainerState.tabIndex = value; + + // Updates meta tag details when switching between tab bar samples. + metaTagUpdate.update( + outputContainerState.sample.title!, + outputContainerState.sample.control!.title!, + ); + if (model.currentSampleKey == null || model.currentSampleKey != outputContainerState.sample.key) { outputContainerState.refresh(); @@ -1921,9 +1953,15 @@ class SampleOutputContainerState extends State<_SampleOutputContainer> { widget.webLayoutPageState!.popUpKey.currentState! as _PopupState; state._sampleDetails = sample; state._currentWidgetKey = model.currentRenderSample.key as GlobalKey; + final _OutputContainerState outputContainerState = _outputKey.currentState! as _OutputContainerState; + + // Updates meta tag details when expanding a sample to maximized view. + metaTagUpdate.update(sample.title!, sample.control!.title!); + outputContainerState.setState(() {}); + state.refresh(true); } @@ -1937,7 +1975,7 @@ class SampleOutputContainerState extends State<_SampleOutputContainer> { return Size(textPainter.width, textPainter.height); } - /// Get tabs which length is equal to list length + /// Get tabs which length is equal to list length. List _buildTabs(List list) { final List tabs = []; _tabTextWidth = 0; @@ -2537,6 +2575,14 @@ class _TileContainerState extends State<_TileContainer> { list[i].subItems != null ? list[i].subItems![0] as SubItem : list[i]; + + // Updates meta tag details when selecting a sample + // from the left panel in a widget page. + metaTagUpdate.update( + outputContainerState.sample.title!, + outputContainerState.sample.control!.title!, + ); + if (model.currentSampleKey == null || (list[i].key != null ? (model.currentSampleKey != list[i].key || @@ -2674,6 +2720,14 @@ class _TileContainerState extends State<_TileContainer> { list[i].subItems != null ? list[i].subItems![0] as SubItem : list[i]; + + // Updates meta tag details when selecting a sample from + // the left panel in a widget page. + metaTagUpdate.update( + outputContainerState.sample.title!, + outputContainerState.sample.control!.title!, + ); + if (model.currentSampleKey == null || (list[i].key != null ? (model.currentSampleKey != list[i].key || @@ -2898,6 +2952,15 @@ class _PopupState extends State<_Popup> { color: model!.drawerIconColor, ), onPressed: () { + if (_sampleDetails != null) { + // Updates meta tag details when closing + // the maximized sample view and returning + // to normal mode. + metaTagUpdate.update( + _sampleDetails!.title!, + _sampleDetails!.control!.title!, + ); + } model!.needToMaximize = false; final _OutputContainerState outputContainerState = @@ -2907,6 +2970,7 @@ class _PopupState extends State<_Popup> { outputContainerState.renderWidget = _currentWidgetKey?.currentWidget; }); + _sampleDetails = null; refresh(false); }, @@ -2916,7 +2980,14 @@ class _PopupState extends State<_Popup> { ], ), ), - body: _currentWidgetKey?.currentWidget, + body: ListenableBuilder( + listenable: model!, + builder: (BuildContext context, Widget? child) { + final Function? sampleView = + model!.sampleWidget[_sampleDetails!.key]; + return sampleView!(_currentWidgetKey); + }, + ), ) : Container(), ), diff --git a/lib/sample_details.json b/lib/sample_details.json index 21f88588..f976b8eb 100644 --- a/lib/sample_details.json +++ b/lib/sample_details.json @@ -345,6 +345,7 @@ "description": "Plot over 30 chart types ranging from line charts to financial charts", "image": "images/cartesian_types.png", "controlId": 1, + "status": "Updated", "subItems": [ { "type": "parent", @@ -1133,7 +1134,8 @@ "title": "Plot band", "key": "plot_band", "codeLink": "https://github.com/syncfusion/flutter-examples/blob/master/lib/samples/chart/cartesian_charts/axis_features/plot_band.dart", - "needsPropertyPanel": true + "needsPropertyPanel": true, + "status": "Updated" }, { "title": "Plot band recurrence", diff --git a/lib/samples/ai_samples/ai_charts/ai_smart_chart/smart_chart_ai_generator.dart b/lib/samples/ai_samples/ai_charts/ai_smart_chart/smart_chart_ai_generator.dart index 1eb1f49e..0d104bbf 100644 --- a/lib/samples/ai_samples/ai_charts/ai_smart_chart/smart_chart_ai_generator.dart +++ b/lib/samples/ai_samples/ai_charts/ai_smart_chart/smart_chart_ai_generator.dart @@ -725,7 +725,7 @@ class _ChartFromJsonState extends SampleViewState } void updateDataSource() { - final Random random = Random(); + final Random random = Random.secure(); for (final series in chartConfig.seriesList) { for (final data in series.data) { data.yValue = random.nextInt(100) + 50; diff --git a/lib/samples/ai_samples/ai_charts/stock_forecasting.dart b/lib/samples/ai_samples/ai_charts/stock_forecasting.dart index 3abd833e..f3568aae 100644 --- a/lib/samples/ai_samples/ai_charts/stock_forecasting.dart +++ b/lib/samples/ai_samples/ai_charts/stock_forecasting.dart @@ -862,7 +862,7 @@ class _StockForecastingSampleState extends SampleViewState List<_ChartData> _generateDataSource(List<_ChartData> stockData) { final List<_ChartData> items = []; - final Random random = Random(); + final Random random = Random.secure(); // Find the last date in the stock data final DateTime lastDate = stockData[stockData.length - 1].date; diff --git a/lib/samples/ai_samples/ai_datagrid/anomaly_detection.dart b/lib/samples/ai_samples/ai_datagrid/anomaly_detection.dart index 72c5d5cb..5e74236c 100644 --- a/lib/samples/ai_samples/ai_datagrid/anomaly_detection.dart +++ b/lib/samples/ai_samples/ai_datagrid/anomaly_detection.dart @@ -29,6 +29,7 @@ class _AnomalyDetectionSampleState extends SampleViewState late List _machineDetails; bool _isLoading = false; late bool _isWebOrDesktop; + late bool isMaterial3; @override void initState() { @@ -76,6 +77,8 @@ class _AnomalyDetectionSampleState extends SampleViewState model.isFirstTime = false; } }); + + isMaterial3 = model.themeData.useMaterial3; } String _generatePrompt() { @@ -197,6 +200,9 @@ class _AnomalyDetectionSampleState extends SampleViewState ), ), ], + elevation: 0, + scrolledUnderElevation: 0, + backgroundColor: isMaterial3 ? Colors.transparent : null, ), ), body: Stack( @@ -204,6 +210,9 @@ class _AnomalyDetectionSampleState extends SampleViewState SfDataGrid( source: _machineDataSource, columns: _machineDataSource._columns, + columnWidthMode: !_isWebOrDesktop && !model.isMobileResolution + ? ColumnWidthMode.fill + : ColumnWidthMode.none, ), if (_isLoading) const Center(child: CircularProgressIndicator()), ], diff --git a/lib/samples/ai_samples/ai_datagrid/predictive_data_entry.dart b/lib/samples/ai_samples/ai_datagrid/predictive_data_entry.dart index 829346f1..a8f89078 100644 --- a/lib/samples/ai_samples/ai_datagrid/predictive_data_entry.dart +++ b/lib/samples/ai_samples/ai_datagrid/predictive_data_entry.dart @@ -29,6 +29,7 @@ class _PredictiveDataSampleState extends SampleViewState late List _studentDetails; bool _isLoading = false; late bool _isWebOrDesktop; + late bool isMaterial3; @override void initState() { @@ -76,6 +77,8 @@ class _PredictiveDataSampleState extends SampleViewState model.isFirstTime = false; } }); + + isMaterial3 = model.themeData.useMaterial3; } String _generatePrompt() { @@ -213,6 +216,9 @@ class _PredictiveDataSampleState extends SampleViewState ), ), ], + elevation: 0, + scrolledUnderElevation: 0, + backgroundColor: isMaterial3 ? Colors.transparent : null, ), ), body: Stack( @@ -629,10 +635,10 @@ class StudentDataSource extends DataGridSource { columnWidthMode: !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, - width: !isWebOrDesktop - ? 120 - : (isWebOrDesktop && model.isMobileResolution) - ? 150.0 + width: isWebOrDesktop + ? double.nan + : (!isWebOrDesktop && model.isMobileResolution) + ? 120.0 : double.nan, label: Container( padding: const EdgeInsets.all(16.0), @@ -646,9 +652,9 @@ class StudentDataSource extends DataGridSource { columnWidthMode: !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, - width: !isWebOrDesktop - ? 150 - : (isWebOrDesktop && model.isMobileResolution) + width: isWebOrDesktop + ? double.nan + : (!isWebOrDesktop && model.isMobileResolution) ? 150.0 : double.nan, label: Container( @@ -663,9 +669,9 @@ class StudentDataSource extends DataGridSource { columnWidthMode: !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, - width: !isWebOrDesktop - ? 150 - : (isWebOrDesktop && model.isMobileResolution) + width: isWebOrDesktop + ? double.nan + : (!isWebOrDesktop && model.isMobileResolution) ? 150.0 : double.nan, label: Container( @@ -680,9 +686,9 @@ class StudentDataSource extends DataGridSource { columnWidthMode: !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, - width: !isWebOrDesktop - ? 150 - : (isWebOrDesktop && model.isMobileResolution) + width: isWebOrDesktop + ? double.nan + : (!isWebOrDesktop && model.isMobileResolution) ? 150.0 : double.nan, label: Container( @@ -697,9 +703,9 @@ class StudentDataSource extends DataGridSource { columnWidthMode: !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, - width: !isWebOrDesktop - ? 150 - : (isWebOrDesktop && model.isMobileResolution) + width: isWebOrDesktop + ? double.nan + : (!isWebOrDesktop && model.isMobileResolution) ? 150.0 : double.nan, label: Container( diff --git a/lib/samples/ai_samples/ai_datagrid/semantic_filtering.dart b/lib/samples/ai_samples/ai_datagrid/semantic_filtering.dart index ecc5680e..bcc7d624 100644 --- a/lib/samples/ai_samples/ai_datagrid/semantic_filtering.dart +++ b/lib/samples/ai_samples/ai_datagrid/semantic_filtering.dart @@ -25,6 +25,7 @@ class _SemanticFilteringSampleState extends SampleViewState final TextEditingController searchController = TextEditingController(); late bool _isWebOrDesktop; late ValueNotifier isLoadingNotifier; + late bool isMaterial3; @override void initState() { @@ -43,6 +44,7 @@ class _SemanticFilteringSampleState extends SampleViewState model: model, ); isLoadingNotifier = ValueNotifier(false); + isMaterial3 = model.themeData.useMaterial3; } String _generatePrompt() { @@ -139,64 +141,77 @@ Now, generate a similar list for "${searchController.text}". } } + Widget _buildSearchTextField() { + return SizedBox( + width: 250, + height: 45, + child: ValueListenableBuilder( + valueListenable: searchController, + builder: (context, value, child) { + return TextField( + controller: searchController, + onSubmitted: (value) { + if (value.trim().isNotEmpty) { + _sendChatMessage(_generatePrompt()); + } + }, + decoration: InputDecoration( + contentPadding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + hintText: 'Search', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular( + _isWebOrDesktop || !isMaterial3 ? 4 : 100, + ), + ), + suffixIcon: searchController.text.isNotEmpty + ? IconButton( + icon: const Icon(Icons.clear), + onPressed: () { + searchController.clear(); + isLoadingNotifier.value = true; + + Future.delayed(const Duration(seconds: 1), () { + _patientDataSource.clearFilters(); + isLoadingNotifier.value = false; + }); + }, + ) + : null, + ), + onChanged: (value) { + if (value.trim().isEmpty) { + isLoadingNotifier.value = true; + + Future.delayed(const Duration(seconds: 1), () { + _patientDataSource.clearFilters(); + isLoadingNotifier.value = false; + }); + return; + } + }, + ); + }, + ), + ); + } + Widget searchField() { return Padding( - padding: const EdgeInsets.only(left: 12, top: 10), + padding: EdgeInsets.only( + left: 12, + top: 10, + right: !_isWebOrDesktop && model.isMobileResolution ? 12 : 0, + ), child: Row( mainAxisSize: MainAxisSize.min, children: [ - SizedBox( - width: 250, - height: 45, - child: ValueListenableBuilder( - valueListenable: searchController, - builder: (context, value, child) { - return TextField( - controller: searchController, - onSubmitted: (value) { - if (value.trim().isNotEmpty) { - _sendChatMessage(_generatePrompt()); - } - }, - decoration: InputDecoration( - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - hintText: 'Search', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(4), - ), - suffixIcon: searchController.text.isNotEmpty - ? IconButton( - icon: const Icon(Icons.clear), - onPressed: () { - searchController.clear(); - isLoadingNotifier.value = true; - - Future.delayed(const Duration(seconds: 1), () { - _patientDataSource.clearFilters(); - isLoadingNotifier.value = false; - }); - }, - ) - : null, - ), - onChanged: (value) { - if (value.trim().isEmpty) { - isLoadingNotifier.value = true; - - Future.delayed(const Duration(seconds: 1), () { - _patientDataSource.clearFilters(); - isLoadingNotifier.value = false; - }); - return; - } - }, - ); - }, - ), - ), + if (!_isWebOrDesktop && model.isMobileResolution) + Expanded(child: _buildSearchTextField()) + else + _buildSearchTextField(), const SizedBox(width: 10), SizedBox( height: 45, @@ -233,6 +248,9 @@ Now, generate a similar list for "${searchController.text}". ), ), automaticallyImplyLeading: false, + elevation: 0, + scrolledUnderElevation: 0, + backgroundColor: isMaterial3 ? Colors.transparent : null, ), ), body: Column( @@ -242,7 +260,12 @@ Now, generate a similar list for "${searchController.text}". padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), child: Row( mainAxisAlignment: MainAxisAlignment.end, - children: [searchField()], + children: [ + if (!_isWebOrDesktop && model.isMobileResolution) + Expanded(child: searchField()) + else + searchField(), + ], ), ), Expanded( @@ -251,8 +274,10 @@ Now, generate a similar list for "${searchController.text}". SfDataGrid( source: _patientDataSource, columns: _patientDataSource._columns, - columnWidthMode: ColumnWidthMode.auto, - onQueryRowHeight: (details) => 60.0, + columnWidthMode: !_isWebOrDesktop && !model.isMobileResolution + ? ColumnWidthMode.fill + : ColumnWidthMode.auto, + onQueryRowHeight: (details) => _isWebOrDesktop ? 60.0 : 80.0, placeholder: const Center( child: Text( 'No Records Found', @@ -550,9 +575,9 @@ class PatientDataSource extends DataGridSource { columnWidthMode: !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, - width: !isWebOrDesktop - ? 150 - : (isWebOrDesktop && model.isMobileResolution) + width: isWebOrDesktop + ? double.nan + : (!isWebOrDesktop && model.isMobileResolution) ? 150.0 : double.nan, label: Container( @@ -567,9 +592,9 @@ class PatientDataSource extends DataGridSource { columnWidthMode: !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, - width: !isWebOrDesktop - ? 150 - : (isWebOrDesktop && model.isMobileResolution) + width: isWebOrDesktop + ? double.nan + : (!isWebOrDesktop && model.isMobileResolution) ? 150.0 : double.nan, label: Container( @@ -584,9 +609,9 @@ class PatientDataSource extends DataGridSource { columnWidthMode: !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, - width: !isWebOrDesktop - ? 150 - : (isWebOrDesktop && model.isMobileResolution) + width: isWebOrDesktop + ? double.nan + : (!isWebOrDesktop && model.isMobileResolution) ? 150.0 : double.nan, label: Container( @@ -601,9 +626,9 @@ class PatientDataSource extends DataGridSource { columnWidthMode: !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, - width: !isWebOrDesktop - ? 150 - : (isWebOrDesktop && model.isMobileResolution) + width: isWebOrDesktop + ? double.nan + : (!isWebOrDesktop && model.isMobileResolution) ? 150.0 : double.nan, label: Container( @@ -618,9 +643,9 @@ class PatientDataSource extends DataGridSource { columnWidthMode: !isWebOrDesktop ? ColumnWidthMode.none : ColumnWidthMode.fill, - width: !isWebOrDesktop - ? 150 - : (isWebOrDesktop && model.isMobileResolution) + width: isWebOrDesktop + ? double.nan + : (!isWebOrDesktop && model.isMobileResolution) ? 150.0 : double.nan, label: Container( diff --git a/lib/samples/ai_samples/ai_maps/location_finder.dart b/lib/samples/ai_samples/ai_maps/location_finder.dart index 9a9435fd..ce6ad9c5 100644 --- a/lib/samples/ai_samples/ai_maps/location_finder.dart +++ b/lib/samples/ai_samples/ai_maps/location_finder.dart @@ -173,8 +173,7 @@ class _MapLocationFinderState extends SampleViewState ? 'Search location' : 'Hospital in New York', hintStyle: TextStyle( - color: model.themeData.colorScheme.primary - .withValues(alpha: 0.6), + color: model.themeData.colorScheme.secondary, ), filled: true, fillColor: @@ -318,7 +317,7 @@ class _MapLocationFinderState extends SampleViewState ), icon: Icon( Icons.search, - color: model.themeData.colorScheme.primary, + color: model.themeData.colorScheme.secondary, ), onPressed: () => _isButtonVisible ? _handleSearch(_textFieldController.text) diff --git a/lib/samples/barcodes/data_matrix.dart b/lib/samples/barcodes/data_matrix.dart index 905a886d..77547eaa 100644 --- a/lib/samples/barcodes/data_matrix.dart +++ b/lib/samples/barcodes/data_matrix.dart @@ -69,12 +69,12 @@ class _DataMatrixGeneratorState extends SampleViewState { shrinkWrap: true, children: [ Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 10), + padding: const EdgeInsets.fromLTRB(0, 10, 0, 10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'Input value: ', + 'Input value:', overflow: TextOverflow.clip, softWrap: false, style: TextStyle( @@ -83,8 +83,7 @@ class _DataMatrixGeneratorState extends SampleViewState { color: model.textColor, ), ), - Container( - padding: const EdgeInsets.fromLTRB(0, 5, 10, 0), + SizedBox( height: 50, child: Align( alignment: Alignment.bottomLeft, diff --git a/lib/samples/barcodes/qr_code.dart b/lib/samples/barcodes/qr_code.dart index e506dccc..7a0de236 100644 --- a/lib/samples/barcodes/qr_code.dart +++ b/lib/samples/barcodes/qr_code.dart @@ -86,159 +86,128 @@ class _QRCodeGeneratorState extends SampleViewState { builder: (BuildContext context, StateSetter stateSetter) { return ListView( shrinkWrap: true, - padding: const EdgeInsets.fromLTRB(10, 10, 0, 10), + padding: const EdgeInsets.fromLTRB(0, 10, 0, 10), children: [ - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: SizedBox( - height: 100, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Input value: ', - overflow: TextOverflow.clip, - softWrap: false, - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.bold, - color: model.textColor, - ), + SizedBox( + height: 100, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Input value:', + overflow: TextOverflow.clip, + softWrap: false, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + color: model.textColor, ), - Container( - padding: const EdgeInsets.fromLTRB(0, 5, 0, 0), - height: 50, - child: Align( - alignment: Alignment.bottomLeft, - child: Theme( - data: Theme.of( - context, - ).copyWith(canvasColor: model.drawerBackgroundColor), - child: TextField( - style: TextStyle(color: model.textColor), - decoration: InputDecoration( - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide(color: model.textColor), - ), - ), - keyboardType: TextInputType.text, - onChanged: (String text) { - setState(() { - _inputValue = text; - }); - }, - controller: _textEditingController, + ), + Align( + alignment: Alignment.bottomLeft, + child: Theme( + data: Theme.of( + context, + ).copyWith(canvasColor: model.drawerBackgroundColor), + child: TextField( + style: TextStyle(color: model.textColor), + decoration: InputDecoration( + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide(color: model.textColor), ), ), + keyboardType: TextInputType.text, + onChanged: (String text) { + setState(() { + _inputValue = text; + }); + }, + controller: _textEditingController, ), ), - ], - ), + ), + ], ), ), - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: SizedBox( - height: 50, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Expanded( - child: Text( - 'Input mode:', - overflow: TextOverflow.clip, - softWrap: false, - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.bold, - color: model.textColor, - ), - ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + 'Input mode:', + overflow: TextOverflow.clip, + softWrap: false, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + color: model.textColor, ), - Expanded( - child: Container( - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _selectedInputMode, - items: _encoding.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'binary', - child: Text( - value, - textAlign: TextAlign.center, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (String? value) { - _onInputModeChanged(value.toString()); - stateSetter(() {}); - }, - ), - ), - ), - ], + ), ), - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: SizedBox( - height: 70, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Expanded( + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, + ), + value: _selectedInputMode, + items: _encoding.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'binary', child: Text( - 'Error level: ', - overflow: TextOverflow.clip, - softWrap: false, - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.bold, - color: model.textColor, - ), + value, + textAlign: TextAlign.center, + style: TextStyle(color: model.textColor), ), + ); + }).toList(), + onChanged: (String? value) { + _onInputModeChanged(value.toString()); + stateSetter(() {}); + }, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + 'Error level:', + overflow: TextOverflow.clip, + softWrap: false, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + color: model.textColor, ), - Expanded( - child: Container( - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _selectedErrorCorrectionLevel, - items: _errorCorrectionLevels.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'quartile', - child: Text( - value, - textAlign: TextAlign.center, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (String? value) { - _onErrorCorrectionLevelChanged(value.toString()); - stateSetter(() {}); - }, - ), + ), + ), + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, + ), + value: _selectedErrorCorrectionLevel, + items: _errorCorrectionLevels.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'quartile', + child: Text( + value, + textAlign: TextAlign.center, + style: TextStyle(color: model.textColor), ), - ), - ], + ); + }).toList(), + onChanged: (String? value) { + _onErrorCorrectionLevelChanged(value.toString()); + stateSetter(() {}); + }, ), - ), + ], ), ], ); diff --git a/lib/samples/calendar/agenda_view.dart b/lib/samples/calendar/agenda_view.dart index 7af36472..b28dcc33 100644 --- a/lib/samples/calendar/agenda_view.dart +++ b/lib/samples/calendar/agenda_view.dart @@ -99,7 +99,7 @@ class _AgendaViewCalendarState extends SampleViewState { colorCollection.add(const Color(0xFF0A8043)); final List<_Meeting> meetings = <_Meeting>[]; - final Random random = Random(); + final Random random = Random.secure(); final DateTime rangeStartDate = DateTime.now().add( const Duration(days: -(365 ~/ 2)), ); diff --git a/lib/samples/calendar/airfare.dart b/lib/samples/calendar/airfare.dart index 313d6e7d..544319f0 100644 --- a/lib/samples/calendar/airfare.dart +++ b/lib/samples/calendar/airfare.dart @@ -184,7 +184,7 @@ class _AirFareCalendarCalendarState extends SampleViewState { BuildContext buildContext, MonthCellDetails details, ) { - final Random random = Random(); + final Random random = Random.secure(); final bool isToday = isSameDate(details.date, DateTime.now()); final AirFare airFare = _airFareDataCollection[random.nextInt(100)]; final Color defaultColor = diff --git a/lib/samples/calendar/appointment_editor.dart b/lib/samples/calendar/appointment_editor.dart index 6d14d26e..fd26f430 100644 --- a/lib/samples/calendar/appointment_editor.dart +++ b/lib/samples/calendar/appointment_editor.dart @@ -470,7 +470,7 @@ class _CalendarAppointmentEditorState extends SampleViewState { _timeZoneCollection.add('Yakutsk Standard Time'); final DateTime today = DateTime.now(); - final Random random = Random(); + final Random random = Random.secure(); for (int month = -1; month < 2; month++) { for (int day = -5; day < 5; day++) { for (int hour = 9; hour < 18; hour += 5) { @@ -2285,187 +2285,62 @@ class _SelectRuleDialogState extends State<_SelectRuleDialog> { Container( width: 360, padding: const EdgeInsets.only(bottom: 10), - child: Column( - children: [ - RadioListTile<_SelectRule>( - title: const Text('Does not repeat'), - value: _SelectRule.doesNotRepeat, - groupValue: _rule, - toggleable: true, - activeColor: widget.model.primaryColor, - onChanged: (_SelectRule? value) { - setState(() { - if (value != null) { - _rule = value; - widget.recurrenceProperties = null; - widget.onChanged( - PickerChangedDetails(selectedRule: _rule), - ); - } - }); - Navigator.pop(context, widget.recurrenceProperties); - }, - ), - RadioListTile<_SelectRule>( - title: const Text('Every day'), - value: _SelectRule.everyDay, - toggleable: true, - groupValue: _rule, - activeColor: widget.model.primaryColor, - onChanged: (_SelectRule? value) { - setState(() { - if (value != null) { - _rule = value; - widget.recurrenceProperties = RecurrenceProperties( - startDate: _startDate, - ); - widget.recurrenceProperties!.recurrenceType = - RecurrenceType.daily; - widget.recurrenceProperties!.interval = 1; - widget.recurrenceProperties!.recurrenceRange = - RecurrenceRange.noEndDate; - widget.onChanged( - PickerChangedDetails(selectedRule: _rule), - ); - } - }); - Navigator.pop(context, widget.recurrenceProperties); - }, - ), - RadioListTile<_SelectRule>( - title: const Text('Every week'), - value: _SelectRule.everyWeek, - toggleable: true, - groupValue: _rule, - activeColor: widget.model.primaryColor, - onChanged: (_SelectRule? value) { - setState(() { - if (value != null) { - _rule = value; - widget.recurrenceProperties = RecurrenceProperties( - startDate: _startDate, - ); - widget.recurrenceProperties!.recurrenceType = - RecurrenceType.weekly; - widget.recurrenceProperties!.interval = 1; - widget.recurrenceProperties!.recurrenceRange = - RecurrenceRange.noEndDate; - widget.recurrenceProperties!.weekDays = - _startDate.weekday == 1 - ? [WeekDays.monday] - : _startDate.weekday == 2 - ? [WeekDays.tuesday] - : _startDate.weekday == 3 - ? [WeekDays.wednesday] - : _startDate.weekday == 4 - ? [WeekDays.thursday] - : _startDate.weekday == 5 - ? [WeekDays.friday] - : _startDate.weekday == 6 - ? [WeekDays.saturday] - : [WeekDays.sunday]; - widget.onChanged( - PickerChangedDetails(selectedRule: _rule), - ); - } - }); - Navigator.pop(context, widget.recurrenceProperties); - }, - ), - RadioListTile<_SelectRule>( - title: const Text('Every month'), - value: _SelectRule.everyMonth, - toggleable: true, - groupValue: _rule, - activeColor: widget.model.primaryColor, - onChanged: (_SelectRule? value) { - setState(() { - if (value != null) { - _rule = value; - widget.recurrenceProperties = RecurrenceProperties( - startDate: _startDate, - ); - widget.recurrenceProperties!.recurrenceType = - RecurrenceType.monthly; - widget.recurrenceProperties!.interval = 1; - widget.recurrenceProperties!.recurrenceRange = - RecurrenceRange.noEndDate; - widget.recurrenceProperties!.dayOfMonth = - widget.selectedAppointment!.startTime.day; - widget.onChanged( - PickerChangedDetails(selectedRule: _rule), - ); - } - }); - Navigator.pop(context, widget.recurrenceProperties); - }, - ), - RadioListTile<_SelectRule>( - title: const Text('Every year'), - value: _SelectRule.everyYear, - toggleable: true, - groupValue: _rule, - activeColor: widget.model.primaryColor, - onChanged: (_SelectRule? value) { - setState(() { - if (value != null) { - _rule = value; - widget.recurrenceProperties = RecurrenceProperties( - startDate: _startDate, - ); - widget.recurrenceProperties!.recurrenceType = - RecurrenceType.yearly; - widget.recurrenceProperties!.interval = 1; - widget.recurrenceProperties!.recurrenceRange = - RecurrenceRange.noEndDate; - widget.recurrenceProperties!.month = - widget.selectedAppointment!.startTime.month; - widget.recurrenceProperties!.dayOfMonth = - widget.selectedAppointment!.startTime.day; - widget.onChanged( - PickerChangedDetails(selectedRule: _rule), - ); - } - }); + child: RadioGroup<_SelectRule>( + groupValue: _rule, + onChanged: (_SelectRule? value) async { + dynamic properties; + if (value != null && value == _SelectRule.custom) { + properties = await _navigateToCustomRule(context); + } + _handleSpecificRuleLogics(value, properties); + if (context.mounted && value != null) { + if (value == _SelectRule.custom) { + Navigator.pop(context, properties); + } else { Navigator.pop(context, widget.recurrenceProperties); - }, - ), - RadioListTile<_SelectRule>( - title: const Text('Custom'), - value: _SelectRule.custom, - toggleable: true, - groupValue: _rule, - activeColor: widget.model.primaryColor, - onChanged: (_SelectRule? value) async { - final dynamic properties = await Navigator.push( - context, - MaterialPageRoute( - builder: (BuildContext context) => _CustomRule( - widget.model, - widget.selectedAppointment!, - widget.appointmentColor, - widget.events, - widget.recurrenceProperties, - ), - ), - ); - if (properties != widget.recurrenceProperties) { - setState(() { - _rule = _SelectRule.custom; - widget.onChanged( - PickerChangedDetails(selectedRule: _rule), - ); - }); - } - if (!mounted) { - return; - } - if (context.mounted) { - Navigator.pop(context, properties); - } - }, - ), - ], + } + } + }, + child: Column( + children: [ + RadioListTile<_SelectRule>( + title: const Text('Does not repeat'), + value: _SelectRule.doesNotRepeat, + toggleable: true, + activeColor: widget.model.primaryColor, + ), + RadioListTile<_SelectRule>( + title: const Text('Every day'), + value: _SelectRule.everyDay, + toggleable: true, + activeColor: widget.model.primaryColor, + ), + RadioListTile<_SelectRule>( + title: const Text('Every week'), + value: _SelectRule.everyWeek, + toggleable: true, + activeColor: widget.model.primaryColor, + ), + RadioListTile<_SelectRule>( + title: const Text('Every month'), + value: _SelectRule.everyMonth, + toggleable: true, + activeColor: widget.model.primaryColor, + ), + RadioListTile<_SelectRule>( + title: const Text('Every year'), + value: _SelectRule.everyYear, + toggleable: true, + activeColor: widget.model.primaryColor, + ), + RadioListTile<_SelectRule>( + title: const Text('Custom'), + value: _SelectRule.custom, + toggleable: true, + activeColor: widget.model.primaryColor, + ), + ], + ), ), ), ], @@ -2473,6 +2348,134 @@ class _SelectRuleDialogState extends State<_SelectRuleDialog> { ), ); } + + void _handleSpecificRuleLogics(_SelectRule? value, properties) { + setState(() { + if (value != null) { + switch (value) { + case _SelectRule.doesNotRepeat: + { + _doesNotRepeatRule(value); + break; + } + case _SelectRule.everyDay: + { + _everyDayRule(value); + break; + } + case _SelectRule.everyWeek: + { + _everyWeekRule(value); + break; + } + case _SelectRule.everyMonth: + { + _everyMonthRule(value); + break; + } + case _SelectRule.everyYear: + { + _everyYearRule(value); + break; + } + case _SelectRule.custom: + { + _onChangedCustomRule(properties); + if (!mounted) { + return; + } + break; + } + } + } + }); + } + + void _onChangedCustomRule(properties) { + if (properties != widget.recurrenceProperties) { + _rule = _SelectRule.custom; + widget.onChanged(PickerChangedDetails(selectedRule: _rule)); + } + } + + Future _navigateToCustomRule(BuildContext context) async { + final dynamic properties = await Navigator.push( + context, + MaterialPageRoute( + builder: (BuildContext context) => _CustomRule( + widget.model, + widget.selectedAppointment!, + widget.appointmentColor, + widget.events, + widget.recurrenceProperties, + ), + ), + ); + return properties; + } + + void _everyYearRule(_SelectRule value) { + _rule = value; + widget.recurrenceProperties = RecurrenceProperties(startDate: _startDate); + widget.recurrenceProperties!.recurrenceType = RecurrenceType.yearly; + widget.recurrenceProperties!.interval = 1; + widget.recurrenceProperties!.recurrenceRange = RecurrenceRange.noEndDate; + widget.recurrenceProperties!.month = + widget.selectedAppointment!.startTime.month; + widget.recurrenceProperties!.dayOfMonth = + widget.selectedAppointment!.startTime.day; + widget.onChanged(PickerChangedDetails(selectedRule: _rule)); + } + + void _everyMonthRule(_SelectRule value) { + _rule = value; + widget.recurrenceProperties = RecurrenceProperties(startDate: _startDate); + widget.recurrenceProperties!.recurrenceType = RecurrenceType.monthly; + widget.recurrenceProperties!.interval = 1; + widget.recurrenceProperties!.recurrenceRange = RecurrenceRange.noEndDate; + widget.recurrenceProperties!.dayOfMonth = + widget.selectedAppointment!.startTime.day; + widget.onChanged(PickerChangedDetails(selectedRule: _rule)); + } + + void _everyWeekRule(_SelectRule value) { + _rule = value; + widget.recurrenceProperties = RecurrenceProperties(startDate: _startDate); + widget.recurrenceProperties!.recurrenceType = RecurrenceType.weekly; + widget.recurrenceProperties!.interval = 1; + widget.recurrenceProperties!.recurrenceRange = RecurrenceRange.noEndDate; + widget.recurrenceProperties!.weekDays = _startDate.weekday == 1 + ? [WeekDays.monday] + : _startDate.weekday == 2 + ? [WeekDays.tuesday] + : _startDate.weekday == 3 + ? [WeekDays.wednesday] + : _startDate.weekday == 4 + ? [WeekDays.thursday] + : _startDate.weekday == 5 + ? [WeekDays.friday] + : _startDate.weekday == 6 + ? [WeekDays.saturday] + : [WeekDays.sunday]; + widget.onChanged(PickerChangedDetails(selectedRule: _rule)); + } + + void _everyDayRule(_SelectRule value) { + _rule = value; + widget.recurrenceProperties = RecurrenceProperties(startDate: _startDate); + widget.recurrenceProperties!.recurrenceType = RecurrenceType.daily; + widget.recurrenceProperties!.interval = 1; + widget.recurrenceProperties!.recurrenceRange = RecurrenceRange.noEndDate; + widget.onChanged(PickerChangedDetails(selectedRule: _rule)); + } + + void _doesNotRepeatRule(_SelectRule? value) { + if (value != null) { + _rule = value; + widget.recurrenceProperties = null; + widget.onChanged(PickerChangedDetails(selectedRule: _rule)); + } + } } class _DeleteDialog extends StatefulWidget { @@ -2510,108 +2513,79 @@ class _DeleteDialogState extends State<_DeleteDialog> { child: Container( width: 370, padding: const EdgeInsets.only(bottom: 10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - height: 30, - padding: const EdgeInsets.only(left: 25, top: 5), - child: Text( - 'Delete recurring event', - style: TextStyle( - color: defaultTextColor, - fontWeight: FontWeight.w500, + child: RadioGroup<_Delete>( + groupValue: _delete, + onChanged: (_Delete? value) { + setState(() { + _delete = value!; + }); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + height: 30, + padding: const EdgeInsets.only(left: 25, top: 5), + child: Text( + 'Delete recurring event', + style: TextStyle( + color: defaultTextColor, + fontWeight: FontWeight.w500, + ), ), ), - ), - Container(width: 20), - RadioListTile<_Delete>( - title: const Text('This event'), - value: _Delete.event, - groupValue: _delete, - activeColor: widget.model.primaryColor, - onChanged: (_Delete? value) { - setState(() { - _delete = value!; - }); - }, - ), - RadioListTile<_Delete>( - title: const Text('All events'), - value: _Delete.series, - groupValue: _delete, - activeColor: widget.model.primaryColor, - onChanged: (_Delete? value) { - setState(() { - _delete = value!; - }); - }, - ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - RawMaterialButton( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(4)), - ), - onPressed: () { - Navigator.pop(context); - }, - child: Text( - 'Cancel', - style: TextStyle( - color: widget.model.primaryColor, - fontWeight: FontWeight.w500, + Container(width: 20), + RadioListTile<_Delete>( + title: const Text('This event'), + value: _Delete.event, + activeColor: widget.model.primaryColor, + ), + RadioListTile<_Delete>( + title: const Text('All events'), + value: _Delete.series, + activeColor: widget.model.primaryColor, + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + RawMaterialButton( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4)), + ), + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Cancel', + style: TextStyle( + color: widget.model.primaryColor, + fontWeight: FontWeight.w500, + ), ), ), - ), - RawMaterialButton( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(4)), - ), - onPressed: () { - Navigator.pop(context); - final Appointment? parentAppointment = - widget.events.getPatternAppointment( - widget.selectedAppointment, - '', - ) - as Appointment?; - if (_delete == _Delete.event) { - if (widget.selectedAppointment.recurrenceId != null) { - widget.events.appointments!.remove( - widget.selectedAppointment, - ); - widget.events.notifyListeners( - CalendarDataSourceAction.remove, - [widget.selectedAppointment], - ); - } - widget.events.appointments!.removeAt( - widget.events.appointments!.indexOf( - parentAppointment, - ), - ); - widget.events.notifyListeners( - CalendarDataSourceAction.remove, - [parentAppointment!], - ); - parentAppointment.recurrenceExceptionDates != null - ? parentAppointment.recurrenceExceptionDates!.add( - widget.selectedAppointment.startTime, - ) - : parentAppointment.recurrenceExceptionDates = - [ - widget.selectedAppointment.startTime, - ]; - widget.events.appointments!.add(parentAppointment); - widget.events.notifyListeners( - CalendarDataSourceAction.add, - [parentAppointment], - ); - } else { - if (parentAppointment!.recurrenceExceptionDates == - null) { + RawMaterialButton( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4)), + ), + onPressed: () { + Navigator.pop(context); + final Appointment? parentAppointment = + widget.events.getPatternAppointment( + widget.selectedAppointment, + '', + ) + as Appointment?; + if (_delete == _Delete.event) { + if (widget.selectedAppointment.recurrenceId != + null) { + widget.events.appointments!.remove( + widget.selectedAppointment, + ); + widget.events.notifyListeners( + CalendarDataSourceAction.remove, + [widget.selectedAppointment], + ); + } widget.events.appointments!.removeAt( widget.events.appointments!.indexOf( parentAppointment, @@ -2619,53 +2593,78 @@ class _DeleteDialogState extends State<_DeleteDialog> { ); widget.events.notifyListeners( CalendarDataSourceAction.remove, + [parentAppointment!], + ); + parentAppointment.recurrenceExceptionDates != null + ? parentAppointment.recurrenceExceptionDates! + .add(widget.selectedAppointment.startTime) + : parentAppointment.recurrenceExceptionDates = + [ + widget.selectedAppointment.startTime, + ]; + widget.events.appointments!.add(parentAppointment); + widget.events.notifyListeners( + CalendarDataSourceAction.add, [parentAppointment], ); } else { - final List? exceptionDates = - parentAppointment.recurrenceExceptionDates; - for (int i = 0; i < exceptionDates!.length; i++) { - final Appointment? changedOccurrence = widget - .events - .getOccurrenceAppointment( - parentAppointment, - exceptionDates[i], - '', + if (parentAppointment!.recurrenceExceptionDates == + null) { + widget.events.appointments!.removeAt( + widget.events.appointments!.indexOf( + parentAppointment, + ), + ); + widget.events.notifyListeners( + CalendarDataSourceAction.remove, + [parentAppointment], + ); + } else { + final List? exceptionDates = + parentAppointment.recurrenceExceptionDates; + for (int i = 0; i < exceptionDates!.length; i++) { + final Appointment? changedOccurrence = widget + .events + .getOccurrenceAppointment( + parentAppointment, + exceptionDates[i], + '', + ); + if (changedOccurrence != null) { + widget.events.appointments!.remove( + changedOccurrence, ); - if (changedOccurrence != null) { - widget.events.appointments!.remove( - changedOccurrence, - ); - widget.events.notifyListeners( - CalendarDataSourceAction.remove, - [changedOccurrence], - ); + widget.events.notifyListeners( + CalendarDataSourceAction.remove, + [changedOccurrence], + ); + } } + widget.events.appointments!.removeAt( + widget.events.appointments!.indexOf( + parentAppointment, + ), + ); + widget.events.notifyListeners( + CalendarDataSourceAction.remove, + [parentAppointment], + ); } - widget.events.appointments!.removeAt( - widget.events.appointments!.indexOf( - parentAppointment, - ), - ); - widget.events.notifyListeners( - CalendarDataSourceAction.remove, - [parentAppointment], - ); } - } - Navigator.pop(context); - }, - child: Text( - 'Delete', - style: TextStyle( - fontWeight: FontWeight.w500, - color: widget.model.primaryColor, + Navigator.pop(context); + }, + child: Text( + 'Delete', + style: TextStyle( + fontWeight: FontWeight.w500, + color: widget.model.primaryColor, + ), ), ), - ), - ], - ), - ], + ], + ), + ], + ), ), ), ), @@ -2716,231 +2715,229 @@ class _EditDialogState extends State<_EditDialog> { child: Container( width: 370, padding: const EdgeInsets.only(bottom: 10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - height: 30, - padding: const EdgeInsets.only(left: 25, top: 5), - child: Text( - 'Save recurring event', - style: TextStyle( - color: defaultTextColor, - fontWeight: FontWeight.w500, + child: RadioGroup<_Edit>( + groupValue: _edit, + onChanged: (_Edit? value) { + setState(() { + _edit = value!; + }); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + height: 30, + padding: const EdgeInsets.only(left: 25, top: 5), + child: Text( + 'Save recurring event', + style: TextStyle( + color: defaultTextColor, + fontWeight: FontWeight.w500, + ), ), ), - ), - Container(width: 20), - RadioListTile<_Edit>( - title: const Text('This event'), - value: _Edit.event, - groupValue: _edit, - activeColor: widget.model.primaryColor, - onChanged: (_Edit? value) { - setState(() { - _edit = value!; - }); - }, - ), - RadioListTile<_Edit>( - title: const Text('All events'), - value: _Edit.series, - groupValue: _edit, - activeColor: widget.model.primaryColor, - onChanged: (_Edit? value) { - setState(() { - _edit = value!; - }); - }, - ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - RawMaterialButton( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(4)), - ), - onPressed: () { - Navigator.pop(context); - }, - child: Text( - 'Cancel', - style: TextStyle( - color: widget.model.primaryColor, - fontWeight: FontWeight.w500, + Container(width: 20), + RadioListTile<_Edit>( + title: const Text('This event'), + value: _Edit.event, + activeColor: widget.model.primaryColor, + ), + RadioListTile<_Edit>( + title: const Text('All events'), + value: _Edit.series, + activeColor: widget.model.primaryColor, + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + RawMaterialButton( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4)), + ), + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Cancel', + style: TextStyle( + color: widget.model.primaryColor, + fontWeight: FontWeight.w500, + ), ), ), - ), - RawMaterialButton( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(4)), - ), - onPressed: () { - if (_edit == _Edit.event) { - final Appointment? parentAppointment = - widget.events.getPatternAppointment( - widget.selectedAppointment, - '', - ) - as Appointment?; - final Appointment newAppointment = Appointment( - startTime: widget.newAppointment.startTime, - endTime: widget.newAppointment.endTime, - color: widget.newAppointment.color, - notes: widget.newAppointment.notes, - isAllDay: widget.newAppointment.isAllDay, - location: widget.newAppointment.location, - subject: widget.newAppointment.subject, - resourceIds: widget.newAppointment.resourceIds, - id: - widget.selectedAppointment.appointmentType == - AppointmentType.changedOccurrence - ? widget.selectedAppointment.id - : null, - recurrenceId: parentAppointment!.id, - startTimeZone: widget.newAppointment.startTimeZone, - endTimeZone: widget.newAppointment.endTimeZone, - ); - parentAppointment.recurrenceExceptionDates != null - ? parentAppointment.recurrenceExceptionDates!.add( - widget.selectedAppointment.startTime, - ) - : parentAppointment.recurrenceExceptionDates = - [ - widget.selectedAppointment.startTime, - ]; - widget.events.appointments!.removeAt( - widget.events.appointments!.indexOf( - parentAppointment, - ), - ); - widget.events.notifyListeners( - CalendarDataSourceAction.remove, - [parentAppointment], - ); - widget.events.appointments!.add(parentAppointment); - widget.events.notifyListeners( - CalendarDataSourceAction.add, - [parentAppointment], - ); - if (widget.selectedAppointment.appointmentType == - AppointmentType.changedOccurrence) { + RawMaterialButton( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4)), + ), + onPressed: () { + if (_edit == _Edit.event) { + final Appointment? parentAppointment = + widget.events.getPatternAppointment( + widget.selectedAppointment, + '', + ) + as Appointment?; + final Appointment newAppointment = Appointment( + startTime: widget.newAppointment.startTime, + endTime: widget.newAppointment.endTime, + color: widget.newAppointment.color, + notes: widget.newAppointment.notes, + isAllDay: widget.newAppointment.isAllDay, + location: widget.newAppointment.location, + subject: widget.newAppointment.subject, + resourceIds: widget.newAppointment.resourceIds, + id: + widget.selectedAppointment.appointmentType == + AppointmentType.changedOccurrence + ? widget.selectedAppointment.id + : null, + recurrenceId: parentAppointment!.id, + startTimeZone: + widget.newAppointment.startTimeZone, + endTimeZone: widget.newAppointment.endTimeZone, + ); + parentAppointment.recurrenceExceptionDates != null + ? parentAppointment.recurrenceExceptionDates! + .add(widget.selectedAppointment.startTime) + : parentAppointment.recurrenceExceptionDates = + [ + widget.selectedAppointment.startTime, + ]; widget.events.appointments!.removeAt( widget.events.appointments!.indexOf( - widget.selectedAppointment, + parentAppointment, ), ); widget.events.notifyListeners( CalendarDataSourceAction.remove, - [widget.selectedAppointment], + [parentAppointment], ); - } - widget.events.appointments!.add(newAppointment); - widget.events.notifyListeners( - CalendarDataSourceAction.add, - [newAppointment], - ); - } else { - Appointment? parentAppointment = - widget.events.getPatternAppointment( - widget.selectedAppointment, - '', - ) - as Appointment?; - final List? exceptionDates = - parentAppointment!.recurrenceExceptionDates; - if (exceptionDates != null && - exceptionDates.isNotEmpty) { - for (int i = 0; i < exceptionDates.length; i++) { - final Appointment? changedOccurrence = widget - .events - .getOccurrenceAppointment( - parentAppointment, - exceptionDates[i], - '', + widget.events.appointments!.add(parentAppointment); + widget.events.notifyListeners( + CalendarDataSourceAction.add, + [parentAppointment], + ); + if (widget.selectedAppointment.appointmentType == + AppointmentType.changedOccurrence) { + widget.events.appointments!.removeAt( + widget.events.appointments!.indexOf( + widget.selectedAppointment, + ), + ); + widget.events.notifyListeners( + CalendarDataSourceAction.remove, + [widget.selectedAppointment], + ); + } + widget.events.appointments!.add(newAppointment); + widget.events.notifyListeners( + CalendarDataSourceAction.add, + [newAppointment], + ); + } else { + Appointment? parentAppointment = + widget.events.getPatternAppointment( + widget.selectedAppointment, + '', + ) + as Appointment?; + final List? exceptionDates = + parentAppointment!.recurrenceExceptionDates; + if (exceptionDates != null && + exceptionDates.isNotEmpty) { + for (int i = 0; i < exceptionDates.length; i++) { + final Appointment? changedOccurrence = widget + .events + .getOccurrenceAppointment( + parentAppointment, + exceptionDates[i], + '', + ); + if (changedOccurrence != null) { + widget.events.appointments!.remove( + changedOccurrence, ); - if (changedOccurrence != null) { - widget.events.appointments!.remove( - changedOccurrence, - ); - widget.events.notifyListeners( - CalendarDataSourceAction.remove, - [changedOccurrence], - ); + widget.events.notifyListeners( + CalendarDataSourceAction.remove, + [changedOccurrence], + ); + } } } - } - widget.events.appointments!.removeAt( - widget.events.appointments!.indexOf( - parentAppointment, - ), - ); - widget.events.notifyListeners( - CalendarDataSourceAction.remove, - [parentAppointment], - ); - DateTime startDate, endDate; - if (widget.newAppointment.startTime.isBefore( - parentAppointment.startTime, - )) { - startDate = widget.newAppointment.startTime; - endDate = widget.newAppointment.endTime; - } else { - startDate = DateTime( - parentAppointment.startTime.year, - parentAppointment.startTime.month, - parentAppointment.startTime.day, - widget.newAppointment.startTime.hour, - widget.newAppointment.startTime.minute, + widget.events.appointments!.removeAt( + widget.events.appointments!.indexOf( + parentAppointment, + ), ); - endDate = DateTime( - parentAppointment.endTime.year, - parentAppointment.endTime.month, - parentAppointment.endTime.day, - widget.newAppointment.endTime.hour, - widget.newAppointment.endTime.minute, + widget.events.notifyListeners( + CalendarDataSourceAction.remove, + [parentAppointment], + ); + DateTime startDate, endDate; + if (widget.newAppointment.startTime.isBefore( + parentAppointment.startTime, + )) { + startDate = widget.newAppointment.startTime; + endDate = widget.newAppointment.endTime; + } else { + startDate = DateTime( + parentAppointment.startTime.year, + parentAppointment.startTime.month, + parentAppointment.startTime.day, + widget.newAppointment.startTime.hour, + widget.newAppointment.startTime.minute, + ); + endDate = DateTime( + parentAppointment.endTime.year, + parentAppointment.endTime.month, + parentAppointment.endTime.day, + widget.newAppointment.endTime.hour, + widget.newAppointment.endTime.minute, + ); + } + parentAppointment = Appointment( + startTime: startDate, + endTime: endDate, + color: widget.newAppointment.color, + notes: widget.newAppointment.notes, + isAllDay: widget.newAppointment.isAllDay, + location: widget.newAppointment.location, + subject: widget.newAppointment.subject, + resourceIds: widget.newAppointment.resourceIds, + id: parentAppointment.id, + recurrenceRule: + widget.recurrenceProperties == null + ? null + : SfCalendar.generateRRule( + widget.recurrenceProperties!, + startDate, + endDate, + ), + startTimeZone: + widget.newAppointment.startTimeZone, + endTimeZone: widget.newAppointment.endTimeZone, + ); + widget.events.appointments!.add(parentAppointment); + widget.events.notifyListeners( + CalendarDataSourceAction.add, + [parentAppointment], ); } - parentAppointment = Appointment( - startTime: startDate, - endTime: endDate, - color: widget.newAppointment.color, - notes: widget.newAppointment.notes, - isAllDay: widget.newAppointment.isAllDay, - location: widget.newAppointment.location, - subject: widget.newAppointment.subject, - resourceIds: widget.newAppointment.resourceIds, - id: parentAppointment.id, - recurrenceRule: widget.recurrenceProperties == null - ? null - : SfCalendar.generateRRule( - widget.recurrenceProperties!, - startDate, - endDate, - ), - startTimeZone: widget.newAppointment.startTimeZone, - endTimeZone: widget.newAppointment.endTimeZone, - ); - widget.events.appointments!.add(parentAppointment); - widget.events.notifyListeners( - CalendarDataSourceAction.add, - [parentAppointment], - ); - } - Navigator.pop(context); - Navigator.pop(context); - }, - child: Text( - 'Save', - style: TextStyle( - fontWeight: FontWeight.w500, - color: widget.model.primaryColor, + Navigator.pop(context); + Navigator.pop(context); + }, + child: Text( + 'Save', + style: TextStyle( + fontWeight: FontWeight.w500, + color: widget.model.primaryColor, + ), ), ), - ), - ], - ), - ], + ], + ), + ], + ), ), ), ), @@ -3708,205 +3705,224 @@ class _CustomRuleState extends State<_CustomRule> { ), ), if (_selectedRecurrenceType == 'year') const Divider(thickness: 1), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Padding( - padding: EdgeInsets.only(left: 15, top: 15), - child: Text('ENDS'), - ), - RadioListTile<_EndRule>( - contentPadding: const EdgeInsets.only(left: 7), - title: const Text('Never'), - value: _EndRule.never, - groupValue: _endRule, - activeColor: widget.model.primaryColor, - onChanged: (_EndRule? value) { - setState(() { - _endRule = _EndRule.never; - _rangeNoEndDate(); - }); - }, - ), - const Divider(indent: 50, height: 1.0, thickness: 1), - RadioListTile<_EndRule>( - contentPadding: const EdgeInsets.only(left: 7), - title: Row( - children: [ - const Text('On'), - Container( - margin: const EdgeInsets.only(left: 5), - width: 110, - height: 40, - decoration: BoxDecoration( - color: Colors.grey.withValues(alpha: 0.1), - borderRadius: BorderRadius.circular(3), - ), - child: ButtonTheme( - minWidth: 30.0, - child: MaterialButton( - elevation: 0, - focusElevation: 0, - highlightElevation: 0, - disabledElevation: 0, - hoverElevation: 0, - onPressed: () async { - final DateTime? pickedDate = await showDatePicker( - context: context, - initialDate: _selectedDate, - firstDate: _startDate.isBefore(_firstDate) - ? _startDate - : _firstDate, - currentDate: _selectedDate, - lastDate: DateTime(2050), - builder: (BuildContext context, Widget? child) { - return Theme( - data: ThemeData( - brightness: widget - .model - .themeData - .colorScheme - .brightness, - colorScheme: getColorScheme( - widget.model, - true, - ), - ), - child: child!, - ); - }, - ); - if (pickedDate == null) { - return; - } - setState(() { - _endRule = _EndRule.endDate; - _recurrenceProperties!.recurrenceRange = - RecurrenceRange.endDate; - _selectedDate = DateTime( - pickedDate.year, - pickedDate.month, - pickedDate.day, - ); - _recurrenceProperties!.endDate = _selectedDate; - }); - }, - shape: const CircleBorder(), - child: Text( - DateFormat('MM/dd/yyyy').format(_selectedDate), - style: TextStyle( - fontSize: 13, - color: defaultTextColor, - fontWeight: FontWeight.w400, - ), - ), - ), - ), - ), - ], + RadioGroup<_EndRule>( + groupValue: _endRule, + onChanged: (_EndRule? value) { + if (value != null) { + setState(() { + switch (value) { + case _EndRule.never: + { + _neverEndRule(); + break; + } + case _EndRule.endDate: + { + _endDateEndRule(value); + break; + } + case _EndRule.count: + { + _countEndRule(value); + break; + } + } + }); + } + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Padding( + padding: EdgeInsets.only(left: 15, top: 15), + child: Text('ENDS'), ), - value: _EndRule.endDate, - groupValue: _endRule, - activeColor: widget.model.primaryColor, - onChanged: (_EndRule? value) { - setState(() { - _endRule = value; - _rangeEndDate(); - }); - }, - ), - const Divider(indent: 50, height: 1.0, thickness: 1), - SizedBox( - height: 40, - child: RadioListTile<_EndRule>( + RadioListTile<_EndRule>( + contentPadding: const EdgeInsets.only(left: 7), + title: const Text('Never'), + value: _EndRule.never, + activeColor: widget.model.primaryColor, + ), + const Divider(indent: 50, height: 1.0, thickness: 1), + RadioListTile<_EndRule>( contentPadding: const EdgeInsets.only(left: 7), title: Row( children: [ - const Text('After'), + const Text('On'), Container( - height: 40, - width: 60, - padding: const EdgeInsets.only(left: 5, bottom: 10), margin: const EdgeInsets.only(left: 5), - alignment: Alignment.topCenter, + width: 110, + height: 40, decoration: BoxDecoration( color: Colors.grey.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(3), ), - child: TextField( - readOnly: _endRule != _EndRule.count, - controller: TextEditingController.fromValue( - TextEditingValue( - text: _count.toString(), - selection: TextSelection.collapsed( - offset: _count.toString().length, + child: ButtonTheme( + minWidth: 30.0, + child: MaterialButton( + elevation: 0, + focusElevation: 0, + highlightElevation: 0, + disabledElevation: 0, + hoverElevation: 0, + onPressed: () async { + final DateTime? pickedDate = await showDatePicker( + context: context, + initialDate: _selectedDate, + firstDate: _startDate.isBefore(_firstDate) + ? _startDate + : _firstDate, + currentDate: _selectedDate, + lastDate: DateTime(2050), + builder: (BuildContext context, Widget? child) { + return Theme( + data: ThemeData( + brightness: widget + .model + .themeData + .colorScheme + .brightness, + colorScheme: getColorScheme( + widget.model, + true, + ), + ), + child: child!, + ); + }, + ); + if (pickedDate == null) { + return; + } + setState(() { + _endRule = _EndRule.endDate; + _recurrenceProperties!.recurrenceRange = + RecurrenceRange.endDate; + _selectedDate = DateTime( + pickedDate.year, + pickedDate.month, + pickedDate.day, + ); + _recurrenceProperties!.endDate = _selectedDate; + }); + }, + shape: const CircleBorder(), + child: Text( + DateFormat('MM/dd/yyyy').format(_selectedDate), + style: TextStyle( + fontSize: 13, + color: defaultTextColor, + fontWeight: FontWeight.w400, ), ), ), - cursorColor: widget.model.primaryColor, - onTap: () { - setState(() { - _endRule = _EndRule.count; - }); - }, - onChanged: (String value) async { - if (value != null && value.isNotEmpty) { - _count = int.parse(value); - if (_count == 0) { - _count = 1; - } else if (_count! >= 999) { - setState(() { - _count = 999; - }); - } - } else if (value.isEmpty || value == null) { - _count = 1; - } - _endRule = _EndRule.count; - _recurrenceProperties!.recurrenceRange = - RecurrenceRange.count; - _recurrenceProperties!.recurrenceCount = _count!; - }, - keyboardType: TextInputType.number, - // ignore: always_specify_types - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly, - ], - style: TextStyle( - fontSize: 13, - color: defaultTextColor, - fontWeight: FontWeight.w400, - ), - textAlign: TextAlign.center, - decoration: const InputDecoration( - border: InputBorder.none, - ), ), ), - Container(width: 10), - const Text('occurrence'), ], ), - value: _EndRule.count, - groupValue: _endRule, + value: _EndRule.endDate, activeColor: widget.model.primaryColor, - onChanged: (_EndRule? value) { - setState(() { - _endRule = value; - _recurrenceProperties!.recurrenceRange = - RecurrenceRange.count; - _recurrenceProperties!.recurrenceCount = _count!; - }); - }, ), - ), - ], + const Divider(indent: 50, height: 1.0, thickness: 1), + SizedBox( + height: 40, + child: RadioListTile<_EndRule>( + contentPadding: const EdgeInsets.only(left: 7), + title: Row( + children: [ + const Text('After'), + Container( + height: 40, + width: 60, + padding: const EdgeInsets.only(left: 5, bottom: 10), + margin: const EdgeInsets.only(left: 5), + alignment: Alignment.topCenter, + decoration: BoxDecoration( + color: Colors.grey.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(3), + ), + child: TextField( + readOnly: _endRule != _EndRule.count, + controller: TextEditingController.fromValue( + TextEditingValue( + text: _count.toString(), + selection: TextSelection.collapsed( + offset: _count.toString().length, + ), + ), + ), + cursorColor: widget.model.primaryColor, + onTap: () { + setState(() { + _endRule = _EndRule.count; + }); + }, + onChanged: (String value) async { + if (value != null && value.isNotEmpty) { + _count = int.parse(value); + if (_count == 0) { + _count = 1; + } else if (_count! >= 999) { + setState(() { + _count = 999; + }); + } + } else if (value.isEmpty || value == null) { + _count = 1; + } + _endRule = _EndRule.count; + _recurrenceProperties!.recurrenceRange = + RecurrenceRange.count; + _recurrenceProperties!.recurrenceCount = _count!; + }, + keyboardType: TextInputType.number, + // ignore: always_specify_types + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + ], + style: TextStyle( + fontSize: 13, + color: defaultTextColor, + fontWeight: FontWeight.w400, + ), + textAlign: TextAlign.center, + decoration: const InputDecoration( + border: InputBorder.none, + ), + ), + ), + Container(width: 10), + const Text('occurrence'), + ], + ), + value: _EndRule.count, + activeColor: widget.model.primaryColor, + ), + ), + ], + ), ), ], ), ); } + void _countEndRule(_EndRule value) { + _endRule = value; + _recurrenceProperties!.recurrenceRange = RecurrenceRange.count; + _recurrenceProperties!.recurrenceCount = _count!; + } + + void _endDateEndRule(_EndRule value) { + _endRule = value; + _rangeEndDate(); + } + + void _neverEndRule() { + _endRule = _EndRule.never; + _rangeNoEndDate(); + } + @override Widget build(BuildContext context) { return Theme( diff --git a/lib/samples/calendar/calendar_loadmore.dart b/lib/samples/calendar/calendar_loadmore.dart index bf6b9a15..a1f14b32 100644 --- a/lib/samples/calendar/calendar_loadmore.dart +++ b/lib/samples/calendar/calendar_loadmore.dart @@ -149,7 +149,7 @@ class _LoadMoreCalendarState extends SampleViewState { colorCollection.add(const Color(0xFF636363)); colorCollection.add(const Color(0xFF0A8043)); - final Random random = Random(); + final Random random = Random.secure(); _dataCollection = >{}; final DateTime today = DateTime.now(); final DateTime rangeStartDate = DateTime( diff --git a/lib/samples/calendar/customization.dart b/lib/samples/calendar/customization.dart index f4cd11be..64467e76 100644 --- a/lib/samples/calendar/customization.dart +++ b/lib/samples/calendar/customization.dart @@ -111,7 +111,7 @@ class _CustomizationCalendarState extends SampleViewState { void _onViewChanged(ViewChangedDetails visibleDatesChangedDetails) { final List<_Meeting> appointment = <_Meeting>[]; _events.appointments.clear(); - final Random random = Random(); + final Random random = Random.secure(); /// Remove the scroll bar on sample while change the view from /// month view or change the view to month view. diff --git a/lib/samples/calendar/drag_and_drop_calendar.dart b/lib/samples/calendar/drag_and_drop_calendar.dart index 7fc73d14..f47838dd 100644 --- a/lib/samples/calendar/drag_and_drop_calendar.dart +++ b/lib/samples/calendar/drag_and_drop_calendar.dart @@ -144,7 +144,7 @@ class _DragAndDropCalendarState extends SampleViewState { colorCollection.add(const Color(0xFF0A8043)); final List appointments = []; - final Random random = Random(); + final Random random = Random.secure(); DateTime today = DateTime.now(); final DateTime rangeStartDate = today.add( const Duration(days: -(365 ~/ 2)), diff --git a/lib/samples/calendar/getting_started.dart b/lib/samples/calendar/getting_started.dart index 6121c14a..56fdd50d 100644 --- a/lib/samples/calendar/getting_started.dart +++ b/lib/samples/calendar/getting_started.dart @@ -151,7 +151,7 @@ class GettingStartedCalendarState extends SampleViewState { void _onViewChanged(ViewChangedDetails visibleDatesChangedDetails) { final List<_Meeting> appointment = <_Meeting>[]; _events.appointments.clear(); - final Random random = Random(); + final Random random = Random.secure(); final List blockedDates = []; if (_calendarController.view == CalendarView.month || _calendarController.view == CalendarView.timelineMonth) { @@ -496,92 +496,82 @@ class GettingStartedCalendarState extends SampleViewState { ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( - flex: model.isWebFullView ? 5 : 6, child: Text( - model.isWebFullView - ? 'View navigation \nmode' - : 'View navigation mode', - softWrap: false, + 'View navigation mode', style: TextStyle(fontSize: 16.0, color: model.textColor), ), ), - Expanded( - flex: model.isWebFullView ? 5 : 4, - child: Container( - padding: const EdgeInsets.only(left: 60), - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _viewNavigationModeString, - items: _viewNavigationModeList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'Snap', - child: Text( - value, - textAlign: TextAlign.center, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - onViewNavigationModeChange(value); - stateSetter(() {}); - }, + Container( + padding: const EdgeInsets.only(left: 60), + alignment: Alignment.bottomLeft, + child: DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, ), + value: _viewNavigationModeString, + items: _viewNavigationModeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'Snap', + child: Text( + value, + textAlign: TextAlign.center, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (dynamic value) { + onViewNavigationModeChange(value); + stateSetter(() {}); + }, ), ), ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: model.isWebFullView ? 5 : 6, + Flexible( child: Text( 'Number of days', - softWrap: false, style: TextStyle(fontSize: 16.0, color: model.textColor), ), ), - Expanded( - flex: model.isWebFullView ? 6 : 4, - child: Container( - padding: const EdgeInsets.only(left: 60), - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _numberOfDaysString, - items: - (_calendarController.view == CalendarView.workWeek - ? _numberOfDaysListWorkWeek - : _numberOfDaysList) - .map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'default', - child: Text( - value, - textAlign: TextAlign.center, - style: TextStyle(color: model.textColor), - ), - ); - }) - .toList(), - onChanged: (dynamic value) { - customNumberOfDaysInView(value); - stateSetter(() {}); - }, + Container( + padding: const EdgeInsets.only(left: 60), + alignment: Alignment.bottomLeft, + child: DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, ), + value: _numberOfDaysString, + items: + (_calendarController.view == CalendarView.workWeek + ? _numberOfDaysListWorkWeek + : _numberOfDaysList) + .map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'default', + child: Text( + value, + textAlign: TextAlign.center, + style: TextStyle(color: model.textColor), + ), + ); + }) + .toList(), + onChanged: (dynamic value) { + customNumberOfDaysInView(value); + stateSetter(() {}); + }, ), ), ], diff --git a/lib/samples/calendar/recurrence.dart b/lib/samples/calendar/recurrence.dart index 0d9d7fc4..01609740 100644 --- a/lib/samples/calendar/recurrence.dart +++ b/lib/samples/calendar/recurrence.dart @@ -416,7 +416,7 @@ class RecurrenceCalendarState extends SampleViewState { _colorCollection.add(const Color(0xFF636363)); final List appointments = []; - final Random random = Random(); + final Random random = Random.secure(); final DateTime currentDate = DateTime.now(); final DateTime startTime = DateTime( diff --git a/lib/samples/calendar/resizing_calendar.dart b/lib/samples/calendar/resizing_calendar.dart index f848e905..2f9751b8 100644 --- a/lib/samples/calendar/resizing_calendar.dart +++ b/lib/samples/calendar/resizing_calendar.dart @@ -141,7 +141,7 @@ class _ResizingCalendarState extends SampleViewState { colorCollection.add(const Color(0xFF0A8043)); final List appointments = []; - final Random random = Random(); + final Random random = Random.secure(); DateTime today = DateTime.now(); final DateTime rangeStartDate = today.add( const Duration(days: -(365 ~/ 2)), diff --git a/lib/samples/calendar/schedule_view.dart b/lib/samples/calendar/schedule_view.dart index ca6393c8..44d720bb 100644 --- a/lib/samples/calendar/schedule_view.dart +++ b/lib/samples/calendar/schedule_view.dart @@ -57,7 +57,7 @@ class _ScheduleViewCalendarState extends SampleViewState { colorCollection.add(const Color(0xFF636363)); colorCollection.add(const Color(0xFF0A8043)); - final Random random = Random(); + final Random random = Random.secure(); final DateTime rangeStartDate = DateTime.now().add( const Duration(days: -(365 ~/ 2)), ); diff --git a/lib/samples/calendar/shift_scheduler.dart b/lib/samples/calendar/shift_scheduler.dart index 8d7ed713..1b1e9778 100644 --- a/lib/samples/calendar/shift_scheduler.dart +++ b/lib/samples/calendar/shift_scheduler.dart @@ -417,7 +417,7 @@ class _ShiftSchedulerState extends SampleViewState { /// Method that creates the resource collection for the Calendar, with the /// required information. void _addResources() { - final Random random = Random(); + final Random random = Random.secure(); for (int i = 0; i < _nameCollection.length; i++) { _employeeCollection.add( CalendarResource( @@ -441,7 +441,7 @@ class _ShiftSchedulerState extends SampleViewState { /// required information. void _addSpecialRegions() { final DateTime date = DateTime.now(); - final Random random = Random(); + final Random random = Random.secure(); for (int i = 0; i < _employeeCollection.length; i++) { _specialTimeRegions.add( TimeRegion( @@ -478,7 +478,7 @@ class _ShiftSchedulerState extends SampleViewState { /// Method that creates the collection the data source for Calendar, with /// required information. void _addAppointments() { - final Random random = Random(); + final Random random = Random.secure(); for (int i = 0; i < _employeeCollection.length; i++) { final List employeeIds = [_employeeCollection[i].id]; if (i == _employeeCollection.length - 1) { diff --git a/lib/samples/calendar/special_regions.dart b/lib/samples/calendar/special_regions.dart index a62dde1c..71d6b3c0 100644 --- a/lib/samples/calendar/special_regions.dart +++ b/lib/samples/calendar/special_regions.dart @@ -138,7 +138,7 @@ class _SpecialRegionsCalendarState extends SampleViewState { colorCollection.add(const Color(0xFF636363)); colorCollection.add(const Color(0xFF0A8043)); - final Random random = Random(); + final Random random = Random.secure(); final DateTime rangeStartDate = DateTime.now().add( const Duration(days: -(365 ~/ 2)), ); diff --git a/lib/samples/calendar/timeline_views.dart b/lib/samples/calendar/timeline_views.dart index 1be44965..74032588 100644 --- a/lib/samples/calendar/timeline_views.dart +++ b/lib/samples/calendar/timeline_views.dart @@ -76,7 +76,7 @@ class _TimelineViewsCalendarState extends SampleViewState { void _onViewChanged(ViewChangedDetails visibleDatesChangedDetails) { final List<_Meeting> appointment = <_Meeting>[]; _events.appointments.clear(); - final Random random = Random(); + final Random random = Random.secure(); final List blockedDates = []; if (_calendarController.view == CalendarView.timelineMonth) { for (int i = 0; i < 5; i++) { diff --git a/lib/samples/chart/cartesian_charts/axis_features/axis_animation.dart b/lib/samples/chart/cartesian_charts/axis_features/axis_animation.dart index aa5d35e7..1cf1d1d3 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/axis_animation.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/axis_animation.dart @@ -58,26 +58,24 @@ class _AxisAnimationDefaultState extends SampleViewState { return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Enable axis elements\nanimation', textAlign: TextAlign.start, style: TextStyle(color: model.textColor, fontSize: 16), ), - Padding( - padding: const EdgeInsets.all(8.0), - child: SizedBox( - width: 90, - child: CheckboxListTile( - activeColor: model.primaryColor, - value: _animation, - onChanged: (bool? value) { - setState(() { - _animation = value!; - stateSetter(() {}); - }); - }, - ), + SizedBox( + width: 90, + child: CheckboxListTile( + activeColor: model.primaryColor, + value: _animation, + onChanged: (bool? value) { + setState(() { + _animation = value!; + stateSetter(() {}); + }); + }, ), ), ], @@ -146,7 +144,7 @@ class _AxisAnimationDefaultState extends SampleViewState { } int _createRandomIntData(int min, int max) { - final Random random = Random(); + final Random random = Random.secure(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/axis_features/axis_crossing.dart b/lib/samples/chart/cartesian_charts/axis_features/axis_crossing.dart index 54f19418..a1daedd9 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/axis_crossing.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/axis_crossing.dart @@ -69,13 +69,14 @@ class _AxisCrossingState extends SampleViewState { shrinkWrap: true, children: [ Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Axis ', style: TextStyle(fontSize: 16.0, color: model.textColor), ), Container( - padding: const EdgeInsets.fromLTRB(138, 0, 0, 0), + padding: const EdgeInsets.fromLTRB(138, 0, 20, 0), child: DropdownButton( dropdownColor: model.drawerBackgroundColor, focusColor: Colors.transparent, @@ -102,28 +103,27 @@ class _AxisCrossingState extends SampleViewState { ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Cross at ', style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Container( - padding: const EdgeInsets.fromLTRB(85, 0, 0, 0), - child: CustomDirectionalButtons( - minValue: -8, - maxValue: 8, - initialValue: _crossAt, - onChanged: (double val) => setState(() { - _crossAt = val; - }), - step: 2, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), + CustomDirectionalButtons( + minValue: -8, + maxValue: 8, + initialValue: _crossAt, + onChanged: (double val) => setState(() { + _crossAt = val; + }), + step: 2, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), ), ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Labels near axis line', diff --git a/lib/samples/chart/cartesian_charts/axis_features/customized_axis_label.dart b/lib/samples/chart/cartesian_charts/axis_features/customized_axis_label.dart index 61a5204b..5cf95089 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/customized_axis_label.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/customized_axis_label.dart @@ -71,7 +71,7 @@ class _CustomLabelsEventState extends SampleViewState { _isHours = false; _isMinutes = false; _tooltipBehavior = TooltipBehavior(enable: true); - _random = Random(); + _random = Random.secure(); _chartData = <_LabelData>[ _LabelData(DateTime(2016), 57), _LabelData(DateTime(2017), 70), diff --git a/lib/samples/chart/cartesian_charts/axis_features/interval_type.dart b/lib/samples/chart/cartesian_charts/axis_features/interval_type.dart index 8247112a..e9d255dd 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/interval_type.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/interval_type.dart @@ -334,6 +334,6 @@ class _IntervalTypeState extends SampleViewState { } num _buildRandomIntData(int min, int max) { - final Random random = Random(); + final Random random = Random.secure(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/axis_features/maximum_width_for_labels.dart b/lib/samples/chart/cartesian_charts/axis_features/maximum_width_for_labels.dart index ea6da5e9..86642dd0 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/maximum_width_for_labels.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/maximum_width_for_labels.dart @@ -61,7 +61,7 @@ class ChartMaximumLabelWidthState extends SampleViewState { shrinkWrap: true, children: [ Row( - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Padding( padding: const EdgeInsets.fromLTRB(0, 15, 0, 0), @@ -70,30 +70,26 @@ class ChartMaximumLabelWidthState extends SampleViewState { style: TextStyle(color: model.textColor), ), ), - Container( - padding: !model.isWebFullView - ? const EdgeInsets.fromLTRB(32, 0, 0, 0) - : const EdgeInsets.fromLTRB(42, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 120, - minValue: 1, - initialValue: _xMaximumLabelWidth, - onChanged: (double val) { - setState(() { - _xMaximumLabelWidth = val; - }); - }, - step: 10, - loop: true, - padding: 5.0, - iconColor: model.textColor, - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + CustomDirectionalButtons( + maxValue: 120, + minValue: 1, + initialValue: _xMaximumLabelWidth, + onChanged: (double val) { + setState(() { + _xMaximumLabelWidth = val; + }); + }, + step: 10, + loop: true, + padding: 5.0, + iconColor: model.textColor, + style: TextStyle(fontSize: 16.0, color: model.textColor), ), ], ), SizedBox( child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Enable label extent', @@ -119,29 +115,25 @@ class ChartMaximumLabelWidthState extends SampleViewState { Visibility( visible: _isEnableLabelExtend, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Labels extent', style: TextStyle(color: model.textColor), ), - Container( - padding: !model.isWebFullView - ? const EdgeInsets.fromLTRB(40, 0, 0, 0) - : const EdgeInsets.fromLTRB(50, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 200, - minValue: 1, - initialValue: _xLabelsExtent, - onChanged: (double val) { - setState(() { - _xLabelsExtent = val; - }); - }, - step: 10, - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + CustomDirectionalButtons( + maxValue: 200, + minValue: 1, + initialValue: _xLabelsExtent, + onChanged: (double val) { + setState(() { + _xLabelsExtent = val; + }); + }, + step: 10, + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 16.0, color: model.textColor), ), ], ), diff --git a/lib/samples/chart/cartesian_charts/axis_features/plot_band.dart b/lib/samples/chart/cartesian_charts/axis_features/plot_band.dart index 33308c61..748418d5 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/plot_band.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/plot_band.dart @@ -1,4 +1,5 @@ /// Package import. +import 'dart:math' as math; import 'package:flutter/material.dart'; /// Chart import. @@ -19,14 +20,17 @@ class PlotBandDefault extends SampleView { class _PlotBandDefaultState extends SampleViewState { _PlotBandDefaultState(); - List? _plotBandType; + late List _plotBandType; late bool isHorizontal; late bool isVertical; late String _selectedType; late bool isSegment; late bool isLine; + late bool isCustom; + late bool _shouldRenderAboveSeries; TooltipBehavior? _tooltipBehavior; List? _weatherReport; + List<_ProductSalesComparisonData>? _productSalesComparisonData; @override void initState() { @@ -35,17 +39,23 @@ class _PlotBandDefaultState extends SampleViewState { 'horizontal', 'segment', 'line', - ].toList(); + 'custom', + ]; + isHorizontal = true; isVertical = false; - _selectedType = _plotBandType!.first; + _selectedType = _plotBandType.first; isSegment = false; isLine = false; + isCustom = false; + _shouldRenderAboveSeries = false; + _tooltipBehavior = TooltipBehavior( enable: true, canShowMarker: false, header: '', ); + _weatherReport = [ ChartSampleData(xValue: 'Jan', yValue: 23), ChartSampleData(xValue: 'Feb', yValue: 24), @@ -59,6 +69,16 @@ class _PlotBandDefaultState extends SampleViewState { ChartSampleData(xValue: 'Oct', yValue: 25), ChartSampleData(xValue: 'Nov', yValue: 22), ]; + + _productSalesComparisonData = <_ProductSalesComparisonData>[ + _ProductSalesComparisonData(DateTime(2017, 12, 22), 40), + _ProductSalesComparisonData(DateTime(2017, 12, 26), 70), + _ProductSalesComparisonData(DateTime(2017, 12, 27), 75), + _ProductSalesComparisonData(DateTime(2018, 1, 2), 82), + _ProductSalesComparisonData(DateTime(2018, 1, 3), 53), + _ProductSalesComparisonData(DateTime(2018, 1, 4), 54), + ]; + super.initState(); } @@ -66,49 +86,87 @@ class _PlotBandDefaultState extends SampleViewState { Widget buildSettings(BuildContext context) { return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { - return Row( + return ListView( + shrinkWrap: true, children: [ - Text( - 'Plot band type', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(20, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container(color: const Color(0xFFBDBDBD), height: 1), - value: _selectedType, - items: _plotBandType!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'horizontal', - child: Text( - value, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _onPlotBandModeChange(value.toString()); - stateSetter(() {}); - }, - ), - ), + _buildPlotBandTypeDropdown(stateSetter), + // Show "Above series" checkbox only for custom, segment, and line types. + if (isCustom || isSegment || isLine) + _buildShouldRenderAboveSeries(stateSetter), ], ); }, ); } + Widget _buildPlotBandTypeDropdown(StateSetter stateSetter) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Plot band type', + style: TextStyle(fontSize: 16.0, color: model.textColor), + ), + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container(color: const Color(0xFFBDBDBD), height: 1), + value: _selectedType, + items: List>.generate(_plotBandType.length, ( + int index, + ) { + final String value = _plotBandType[index]; + return DropdownMenuItem( + value: value, + child: Text(value, style: TextStyle(color: model.textColor)), + ); + }), + onChanged: (String? value) { + if (value == null) { + return; + } + _onPlotBandModeChange(value); + stateSetter(() {}); + }, + ), + ], + ); + } + + Widget _buildShouldRenderAboveSeries(StateSetter stateSetter) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Above series', + style: TextStyle(color: model.textColor, fontSize: 16), + ), + SizedBox( + width: 90, + child: CheckboxListTile( + activeColor: model.primaryColor, + value: _shouldRenderAboveSeries, + onChanged: (bool? value) { + _shouldRenderAboveSeries = value ?? false; + stateSetter(() {}); + setState(() {}); + }, + ), + ), + ], + ); + } + @override Widget build(BuildContext context) { return _buildCartesianChart(); } - /// Return the Cartesian Chart with Line series. SfCartesianChart _buildCartesianChart() { + return isCustom ? customPlotBandChart() : defaultPlotBandChart(); + } + + SfCartesianChart defaultPlotBandChart() { final Color yAxisPlotBandTextColor = ((isSegment || isLine) && model != null && @@ -121,7 +179,7 @@ class _PlotBandDefaultState extends SampleViewState { primaryXAxis: CategoryAxis( interval: 1, - /// API for Y axis plot band. + /// API for X axis plot band. /// It returns the multiple plot band to Chart. plotBands: [ PlotBand( @@ -175,6 +233,7 @@ class _PlotBandDefaultState extends SampleViewState { isVisible: isCardView ? false : isSegment, color: const Color.fromRGBO(224, 155, 0, 1), textStyle: const TextStyle(color: Colors.white, fontSize: 17), + shouldRenderAboveSeries: _shouldRenderAboveSeries, ), PlotBand( start: 7.5, @@ -187,6 +246,7 @@ class _PlotBandDefaultState extends SampleViewState { isVisible: isCardView ? false : isSegment, color: const Color.fromRGBO(224, 155, 0, 1), textStyle: const TextStyle(color: Colors.white, fontSize: 17), + shouldRenderAboveSeries: _shouldRenderAboveSeries, ), PlotBand( start: 4.5, @@ -199,6 +259,7 @@ class _PlotBandDefaultState extends SampleViewState { isVisible: isCardView ? false : isSegment, color: const Color.fromRGBO(207, 85, 7, 1), textStyle: const TextStyle(color: Colors.white, fontSize: 17), + shouldRenderAboveSeries: _shouldRenderAboveSeries, ), ], majorGridLines: const MajorGridLines(width: 0), @@ -225,7 +286,6 @@ class _PlotBandDefaultState extends SampleViewState { verticalTextAlignment: isLine ? TextAnchor.start : TextAnchor.middle, - // Padding for plotBand text. verticalTextPadding: isLine ? '-7' : '', borderWidth: isCardView ? 0 @@ -267,7 +327,6 @@ class _PlotBandDefaultState extends SampleViewState { ? const Color.fromRGBO(224, 155, 0, 1) : Colors.black, text: 'Average Temperature', - // Padding for plotBand text. verticalTextPadding: isLine ? '-7' : '', color: const Color.fromRGBO(224, 155, 0, 1), textStyle: @@ -298,7 +357,6 @@ class _PlotBandDefaultState extends SampleViewState { ? const Color.fromRGBO(237, 195, 12, 1) : Colors.black, text: 'Low Temperature', - // padding for plotBand text. verticalTextPadding: isLine ? '-7' : '', color: const Color.fromRGBO(237, 195, 12, 1), textStyle: @@ -318,12 +376,85 @@ class _PlotBandDefaultState extends SampleViewState { ); } - /// Returns the list of Cartesian Line series. + SfCartesianChart customPlotBandChart() { + return SfCartesianChart( + title: ChartTitle( + text: isCardView ? '' : 'Sales comparison with promotional periods', + ), + plotAreaBorderWidth: 0, + primaryXAxis: DateTimeCategoryAxis( + majorGridLines: const MajorGridLines(width: 0), + labelIntersectAction: isCardView + ? AxisLabelIntersectAction.multipleRows + : AxisLabelIntersectAction.rotate45, + plotBands: [ + CustomPlotBand( + start: DateTime(2017, 12, 22), + end: DateTime(2017, 12, 27), + textAngle: 0, + verticalTextPadding: '-10%', + verticalTextAlignment: TextAnchor.start, + text: 'Christmas Sale\nDec 2017', + textStyle: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + patternColor: const Color.fromRGBO(217, 112, 1, 1), + stripeOpacity: _shouldRenderAboveSeries ? 0.75 : 0.55, + stripeWidth: 2, + stripeSpacing: 8, + dashLength: 4, + stripeAngle: 135, + shouldRenderAboveSeries: _shouldRenderAboveSeries, + ), + CustomPlotBand( + textAngle: 0, + start: DateTime(2018, 1, 2), + end: DateTime(2018, 1, 5), + verticalTextPadding: '-10%', + verticalTextAlignment: TextAnchor.start, + text: 'New Year Sale\nJan 2018', + textStyle: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + patternColor: const Color.fromRGBO(255, 100, 150, 1), + stripeOpacity: _shouldRenderAboveSeries ? 0.75 : 0.55, + stripeWidth: 2, + stripeSpacing: 8, + dashLength: 4, + stripeAngle: 135, + shouldRenderAboveSeries: _shouldRenderAboveSeries, + ), + ], + ), + primaryYAxis: const NumericAxis( + labelFormat: '{value}M', + interval: 20, + minimum: 0, + maximum: 100, + majorTickLines: MajorTickLines(size: 0), + axisLine: AxisLine(width: 0), + ), + series: >[ + ColumnSeries<_ProductSalesComparisonData, DateTime>( + dataSource: _productSalesComparisonData, + name: 'Sales', + xValueMapper: (_ProductSalesComparisonData x, int index) => x.year, + yValueMapper: (_ProductSalesComparisonData sales, int index) => + sales.sales, + borderRadius: const BorderRadius.all(Radius.circular(8)), + spacing: 0.15, + ), + ], + tooltipBehavior: _tooltipBehavior, + ); + } + List> _buildLineSeries() { final Color seriesColor = (isSegment || isLine) && - model != null && - model.themeData.colorScheme.brightness == Brightness.light + Theme.of(context).brightness == Brightness.light ? Colors.black54 : Colors.white; return >[ @@ -333,9 +464,10 @@ class _PlotBandDefaultState extends SampleViewState { yValueMapper: (ChartSampleData sales, int index) => sales.yValue, color: seriesColor, name: 'Weather', + width: 3, markerSettings: const MarkerSettings( - height: 5, - width: 5, + height: 7, + width: 7, isVisible: true, color: Color.fromRGBO(192, 108, 132, 1), ), @@ -343,42 +475,156 @@ class _PlotBandDefaultState extends SampleViewState { ]; } - /// Method for updating plot band type in the Chart on change. void _onPlotBandModeChange(String item) { _selectedType = item; + if (_selectedType == 'horizontal') { isVertical = true; isHorizontal = false; isSegment = false; isLine = false; - } - if (_selectedType == 'vertical') { + isCustom = false; + } else if (_selectedType == 'vertical') { isHorizontal = true; isVertical = false; isSegment = false; isLine = false; - } - if (_selectedType == 'segment') { + isCustom = false; + } else if (_selectedType == 'segment') { isHorizontal = false; isVertical = false; isSegment = true; isLine = false; - } - if (_selectedType == 'line') { + isCustom = false; + } else if (_selectedType == 'line') { isHorizontal = false; isVertical = true; isSegment = false; isLine = true; + isCustom = false; + } else if (_selectedType == 'custom') { + isHorizontal = false; + isVertical = false; + isSegment = false; + isLine = false; + isCustom = true; } - setState(() { - /// Update the plat band mode changes. - }); + + setState(() {}); } @override void dispose() { - _plotBandType!.clear(); - _weatherReport!.clear(); + _plotBandType.clear(); + _weatherReport?.clear(); + _productSalesComparisonData?.clear(); super.dispose(); } } + +class _ProductSalesComparisonData { + _ProductSalesComparisonData(this.year, this.sales); + final DateTime year; + final double sales; +} + +class CustomPlotBand extends PlotBand { + const CustomPlotBand({ + super.isVisible = true, + super.start, + super.end, + super.associatedAxisStart, + super.associatedAxisEnd, + super.color = Colors.white, + super.gradient, + super.opacity = 1.0, + super.borderColor = Colors.transparent, + super.borderWidth = 0, + super.dashArray = const [0, 0], + super.text, + super.textStyle, + super.textAngle, + super.verticalTextPadding, + super.horizontalTextPadding, + super.verticalTextAlignment = TextAnchor.middle, + super.horizontalTextAlignment = TextAnchor.middle, + super.isRepeatable = false, + super.repeatEvery = 1, + super.repeatUntil, + super.size, + super.sizeType = DateTimeIntervalType.auto, + super.shouldRenderAboveSeries = false, + this.stripeAngle = 0, + this.stripeWidth = 4.0, + this.stripeSpacing = 4.0, + this.patternColor = Colors.green, + this.stripeOpacity = 1, + this.dashLength = 8.0, + this.gapLength = 4.0, + }); + + final int stripeAngle; + final Color patternColor; + final double stripeWidth; + final double stripeSpacing; + final double stripeOpacity; + final double dashLength; + final double gapLength; + + @override + void drawRect( + Canvas canvas, + Rect rect, + Paint fillPaint, [ + Paint? strokePaint, + ]) { + canvas.save(); + canvas.clipRect(rect); + + // Transparent background for custom pattern. + fillPaint.color = Colors.transparent; + canvas.drawRect(rect, fillPaint); + + // Draw diagonal dashed pattern. + canvas.translate(rect.center.dx, rect.center.dy); + canvas.rotate(stripeAngle * math.pi / 180); + + final double diagonal = math.sqrt( + rect.width * rect.width + rect.height * rect.height, + ); + + final Paint dashPaint = Paint() + ..color = patternColor.withValues(alpha: stripeOpacity) + ..style = PaintingStyle.stroke + ..strokeWidth = stripeWidth + ..strokeCap = StrokeCap.round; + + final double step = stripeWidth + stripeSpacing; + + // Draw dashed lines with gaps. + for (double x = -diagonal; x < diagonal; x += step) { + double y = -diagonal; + while (y < diagonal) { + // Draw dash segment from (x, y) to (x, dashEnd). + final double dashEnd = y + dashLength; + if (dashEnd <= diagonal) { + canvas.drawLine(Offset(x, y), Offset(x, dashEnd), dashPaint); + y = dashEnd + gapLength; + } else { + // Draw remaining portion. + canvas.drawLine(Offset(x, y), Offset(x, diagonal), dashPaint); + break; + } + } + } + + canvas.restore(); + } +} + +/// Sample data type used in the series. +class ChartSampleData { + ChartSampleData({required this.xValue, required this.yValue}); + final String xValue; + final num yValue; +} diff --git a/lib/samples/chart/cartesian_charts/axis_features/plot_offset.dart b/lib/samples/chart/cartesian_charts/axis_features/plot_offset.dart index 3757aae1..dd2472b0 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/plot_offset.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/plot_offset.dart @@ -61,7 +61,6 @@ class _PlotOffsetState extends SampleViewState { @override Widget buildSettings(BuildContext context) { - const double height = 40; final TextStyle textStyle = TextStyle( fontSize: 16.0, color: model.textColor, @@ -84,86 +83,59 @@ class _PlotOffsetState extends SampleViewState { ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('PlotOffset', style: textStyle), - Container( - padding: const EdgeInsets.fromLTRB(50, 0, 0, 0), - height: height, - alignment: Alignment.bottomLeft, - child: Container( - padding: const EdgeInsets.fromLTRB(15, 0, 0, 0), - height: height, - alignment: Alignment.bottomLeft, - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _plotOffsetX ?? 0, - onChanged: (double val) { - setState(() { - _plotOffsetX = val; - if (val == 0) { - _plotOffsetX = null; - } - }); - }, - step: 5, - iconColor: model.textColor, - style: textStyle, - ), - ), + CustomDirectionalButtons( + maxValue: 50, + initialValue: _plotOffsetX ?? 0, + onChanged: (double val) { + setState(() { + _plotOffsetX = val; + if (val == 0) { + _plotOffsetX = null; + } + }); + }, + step: 5, + iconColor: model.textColor, + style: textStyle, ), ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('PlotOffsetStart', style: textStyle), - Container( - padding: const EdgeInsets.fromLTRB(18, 0, 0, 0), - height: height, - alignment: Alignment.bottomLeft, - child: Container( - padding: const EdgeInsets.fromLTRB(15, 0, 0, 0), - height: height, - alignment: Alignment.bottomLeft, - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _plotOffsetStartX ?? 0, - onChanged: (double val) { - setState(() { - _plotOffsetStartX = val; - }); - }, - step: 5, - iconColor: model.textColor, - style: textStyle, - ), - ), + CustomDirectionalButtons( + maxValue: 50, + initialValue: _plotOffsetStartX ?? 0, + onChanged: (double val) { + setState(() { + _plotOffsetStartX = val; + }); + }, + step: 5, + iconColor: model.textColor, + style: textStyle, ), ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('PlotOffsetEnd', style: textStyle), - Container( - padding: const EdgeInsets.fromLTRB(25, 0, 0, 0), - height: height, - alignment: Alignment.bottomLeft, - child: Container( - padding: const EdgeInsets.fromLTRB(15, 0, 0, 0), - height: height, - alignment: Alignment.bottomLeft, - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _plotOffsetEndX ?? 0, - onChanged: (double val) { - setState(() { - _plotOffsetEndX = val; - }); - }, - step: 5, - iconColor: model.textColor, - style: textStyle, - ), - ), + CustomDirectionalButtons( + maxValue: 50, + initialValue: _plotOffsetEndX ?? 0, + onChanged: (double val) { + setState(() { + _plotOffsetEndX = val; + }); + }, + step: 5, + iconColor: model.textColor, + style: textStyle, ), ], ), @@ -180,106 +152,84 @@ class _PlotOffsetState extends SampleViewState { ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('PlotOffset', style: textStyle), - Container( - padding: const EdgeInsets.fromLTRB(50, 0, 0, 0), - height: height, - alignment: Alignment.bottomLeft, - child: Container( - padding: const EdgeInsets.fromLTRB(15, 0, 0, 0), - height: height, - alignment: Alignment.bottomLeft, - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _plotOffsetY ?? 0, - onChanged: (double val) { - setState(() { - _plotOffsetY = val; - if (_plotOffsetY == 0) { - _plotOffsetY = null; - } - }); - }, - step: 5, - iconColor: model.textColor, - style: textStyle, - ), - ), + CustomDirectionalButtons( + maxValue: 50, + initialValue: _plotOffsetY ?? 0, + onChanged: (double val) { + setState(() { + _plotOffsetY = val; + if (_plotOffsetY == 0) { + _plotOffsetY = null; + } + }); + }, + step: 5, + iconColor: model.textColor, + style: textStyle, ), ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('PlotOffsetStart', style: textStyle), - Container( - padding: const EdgeInsets.fromLTRB(18, 0, 0, 0), - height: height, - alignment: Alignment.bottomLeft, - child: Container( - padding: const EdgeInsets.fromLTRB(15, 0, 0, 0), - height: height, - alignment: Alignment.bottomLeft, - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _plotOffsetStartY ?? 0, - onChanged: (double val) { - setState(() { - _plotOffsetStartY = val; - }); - }, - step: 5, - iconColor: model.textColor, - style: textStyle, - ), - ), + CustomDirectionalButtons( + maxValue: 50, + initialValue: _plotOffsetStartY ?? 0, + onChanged: (double val) { + setState(() { + _plotOffsetStartY = val; + }); + }, + step: 5, + iconColor: model.textColor, + style: textStyle, ), ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('PlotOffsetEnd', style: textStyle), - Container( - padding: const EdgeInsets.fromLTRB(25, 0, 0, 0), - height: height, - alignment: Alignment.bottomLeft, - child: Container( - padding: const EdgeInsets.fromLTRB(15, 0, 0, 0), - height: height, - alignment: Alignment.bottomLeft, - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _plotOffsetEndY ?? 0, - onChanged: (double val) { - setState(() { - _plotOffsetEndY = val; - }); - }, - step: 5, - iconColor: model.textColor, - style: textStyle, - ), - ), + CustomDirectionalButtons( + maxValue: 50, + initialValue: _plotOffsetEndY ?? 0, + onChanged: (double val) { + setState(() { + _plotOffsetEndY = val; + }); + }, + step: 5, + iconColor: model.textColor, + style: textStyle, ), ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - 'Inverse series', - style: TextStyle(color: model.textColor, fontSize: 16), + Flexible( + child: Text( + 'Inverse series', + style: TextStyle(color: model.textColor, fontSize: 16), + ), ), - SizedBox( - width: 127, - child: CheckboxListTile( - activeColor: model.primaryColor, - value: _isTransposed, - onChanged: (bool? value) { - setState(() { - _isTransposed = value; - stateSetter(() {}); - }); - }, + Flexible( + child: SizedBox( + width: 127, + child: CheckboxListTile( + activeColor: model.primaryColor, + value: _isTransposed, + onChanged: (bool? value) { + setState(() { + _isTransposed = value; + stateSetter(() {}); + }); + }, + ), ), ), ], diff --git a/lib/samples/chart/cartesian_charts/axis_features/positioning_axis_label.dart b/lib/samples/chart/cartesian_charts/axis_features/positioning_axis_label.dart index 4d094bac..87b706b8 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/positioning_axis_label.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/positioning_axis_label.dart @@ -77,6 +77,7 @@ class _AxisCrossingState extends SampleViewState { shrinkWrap: true, children: [ Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Y Axis', @@ -89,6 +90,7 @@ class _AxisCrossingState extends SampleViewState { ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Label position ', @@ -124,6 +126,7 @@ class _AxisCrossingState extends SampleViewState { ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Label alignment', @@ -159,6 +162,7 @@ class _AxisCrossingState extends SampleViewState { ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'X Axis', @@ -171,6 +175,7 @@ class _AxisCrossingState extends SampleViewState { ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Label position ', @@ -206,6 +211,7 @@ class _AxisCrossingState extends SampleViewState { ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Label alignment', diff --git a/lib/samples/chart/cartesian_charts/axis_features/range_padding.dart b/lib/samples/chart/cartesian_charts/axis_features/range_padding.dart index dfca8700..37c86c8f 100644 --- a/lib/samples/chart/cartesian_charts/axis_features/range_padding.dart +++ b/lib/samples/chart/cartesian_charts/axis_features/range_padding.dart @@ -79,28 +79,22 @@ class _RangePaddingViewState extends SampleViewState { return ListView( shrinkWrap: true, children: [ - Row( - children: [ - Text( - 'X Axis', - style: TextStyle( - fontSize: 16.0, - color: model.textColor, - fontWeight: FontWeight.bold, - ), - ), - ], + Text( + 'X Axis', + style: TextStyle( + fontSize: 16.0, + color: model.textColor, + fontWeight: FontWeight.bold, + ), ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - 'Range padding ', + 'Range padding', style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Container( - padding: const EdgeInsets.fromLTRB(20, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, + Flexible( child: DropdownButton( dropdownColor: model.drawerBackgroundColor, focusColor: Colors.transparent, @@ -126,28 +120,22 @@ class _RangePaddingViewState extends SampleViewState { ), ], ), - Row( - children: [ - Text( - 'Y Axis', - style: TextStyle( - fontSize: 16.0, - color: model.textColor, - fontWeight: FontWeight.bold, - ), - ), - ], + Text( + 'Y Axis', + style: TextStyle( + fontSize: 16.0, + color: model.textColor, + fontWeight: FontWeight.bold, + ), ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - 'Range padding ', + 'Range padding', style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Container( - padding: const EdgeInsets.fromLTRB(20, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, + Flexible( child: DropdownButton( dropdownColor: model.drawerBackgroundColor, focusColor: Colors.transparent, diff --git a/lib/samples/chart/cartesian_charts/axis_types/category/label_placement.dart b/lib/samples/chart/cartesian_charts/axis_types/category/label_placement.dart index 1c1caabf..391d4228 100644 --- a/lib/samples/chart/cartesian_charts/axis_types/category/label_placement.dart +++ b/lib/samples/chart/cartesian_charts/axis_types/category/label_placement.dart @@ -60,42 +60,33 @@ class _CategoryTicksState extends SampleViewState { shrinkWrap: true, children: [ Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - 'Label placement ', + 'Label \nplacement ', style: TextStyle(color: model.textColor, fontSize: 16), ), - Container( - padding: EdgeInsets.fromLTRB( - model.isWebFullView ? 4 : 20, - 0, - 0, - 0, - ), - height: 50, - alignment: Alignment.bottomCenter, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _selectedType, - items: _labelPosition!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'betweenTicks', - child: Text( - value, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _onPositionTypeChange(value.toString()); - stateSetter(() {}); - }, + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, ), + value: _selectedType, + items: _labelPosition!.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'betweenTicks', + child: Text( + value, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (dynamic value) { + _onPositionTypeChange(value.toString()); + stateSetter(() {}); + }, ), ], ), diff --git a/lib/samples/chart/cartesian_charts/chart_types/area/animation_area_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/area/animation_area_chart.dart index 0aecfe78..6337f2d4 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/area/animation_area_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/area/animation_area_chart.dart @@ -82,7 +82,7 @@ class _AnimationAreaDefaultState extends SampleViewState { /// Return the random value in Area series. int _buildRandomInt(int min, int max) { - final Random random = Random(); + final Random random = Random.secure(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/area/area_with_axis_base.dart b/lib/samples/chart/cartesian_charts/chart_types/area/area_with_axis_base.dart index 03a76e52..f2618678 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/area/area_with_axis_base.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/area/area_with_axis_base.dart @@ -50,34 +50,27 @@ class _AxisCrossingBaseValueState extends SampleViewState { return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Axis base value ', style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Container( - padding: const EdgeInsets.fromLTRB(20, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container(color: const Color(0xFFBDBDBD), height: 1), - value: _selectedAxis, - items: _axis!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : '-2 (modified)', - child: Text( - value, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _onAxisTypeChange(value.toString()); - stateSetter(() {}); - }, - ), + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container(color: const Color(0xFFBDBDBD), height: 1), + value: _selectedAxis, + items: _axis!.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : '-2 (modified)', + child: Text(value, style: TextStyle(color: model.textColor)), + ); + }).toList(), + onChanged: (dynamic value) { + _onAxisTypeChange(value.toString()); + stateSetter(() {}); + }, ), ], ); diff --git a/lib/samples/chart/cartesian_charts/chart_types/bar/animation_bar_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/bar/animation_bar_chart.dart index 54a76c72..eb92964e 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/bar/animation_bar_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/bar/animation_bar_chart.dart @@ -65,7 +65,7 @@ class _AnimationBarDefaultState extends SampleViewState { } int _buildRandomInt(int min, int max) { - final Random random = Random(); + final Random random = Random.secure(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/bar/bar_width_and_spacing.dart b/lib/samples/chart/cartesian_charts/chart_types/bar/bar_width_and_spacing.dart index 06326763..823dc8e5 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/bar/bar_width_and_spacing.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/bar/bar_width_and_spacing.dart @@ -50,48 +50,37 @@ class _BarSpacingState extends SampleViewState { shrinkWrap: true, children: [ Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Width ', style: TextStyle(color: model.textColor)), - Container( - padding: const EdgeInsets.fromLTRB(40, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 1, - initialValue: _columnWidth, - onChanged: (double val) => setState(() { - _columnWidth = val; - }), - step: 0.1, - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + CustomDirectionalButtons( + maxValue: 1, + initialValue: _columnWidth, + onChanged: (double val) => setState(() { + _columnWidth = val; + }), + step: 0.1, + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 16.0, color: model.textColor), ), ], ), Row( - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Padding( - padding: const EdgeInsets.fromLTRB(0, 15, 0, 0), - child: Text( - 'Spacing ', - style: TextStyle(color: model.textColor), - ), - ), - Container( - padding: const EdgeInsets.fromLTRB(25, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 1, - initialValue: _columnSpacing, - onChanged: (double val) => setState(() { - _columnSpacing = val; - }), - step: 0.1, - loop: true, - padding: 5.0, - iconColor: model.textColor, - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text('Spacing ', style: TextStyle(color: model.textColor)), + CustomDirectionalButtons( + maxValue: 1, + initialValue: _columnSpacing, + onChanged: (double val) => setState(() { + _columnSpacing = val; + }), + step: 0.1, + loop: true, + padding: 5.0, + iconColor: model.textColor, + style: TextStyle(fontSize: 16.0, color: model.textColor), ), ], ), diff --git a/lib/samples/chart/cartesian_charts/chart_types/bubble/animation_bubble_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/bubble/animation_bubble_chart.dart index 438aaab1..b5dd578d 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/bubble/animation_bubble_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/bubble/animation_bubble_chart.dart @@ -81,12 +81,12 @@ class _AnimationBubbleDefaultState extends SampleViewState { /// To get the random data and return to the chart data source. int _buildRandomInt(int min, int max) { - final Random random = Random(); + final Random random = Random.secure(); return min + random.nextInt(max - min); } void _buildChartData() { - final Random randomValue = Random(); + final Random randomValue = Random.secure(); _chartData = <_ChartData>[]; for (int i = 1; i <= 7; i++) { _chartData!.add( diff --git a/lib/samples/chart/cartesian_charts/chart_types/column/animation_column_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/column/animation_column_chart.dart index 623825da..9e0e6d0a 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/column/animation_column_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/column/animation_column_chart.dart @@ -66,7 +66,7 @@ class _AnimationColumnDefaultState extends SampleViewState { /// Generate random value. int _buildRandomInt(int min, int max) { - final Random random = Random(); + final Random random = Random.secure(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/column/column_width_and_spacing.dart b/lib/samples/chart/cartesian_charts/chart_types/column/column_width_and_spacing.dart index b240b8fb..54c66aab 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/column/column_width_and_spacing.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/column/column_width_and_spacing.dart @@ -75,6 +75,7 @@ class _ColumnSpacingState extends SampleViewState { shrinkWrap: true, children: [ Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Width ', style: TextStyle(color: model.textColor)), Container( @@ -96,31 +97,22 @@ class _ColumnSpacingState extends SampleViewState { ], ), Row( - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Padding( - padding: const EdgeInsets.fromLTRB(0, 15, 0, 0), - child: Text( - 'Spacing ', - style: TextStyle(color: model.textColor), - ), - ), - Container( - padding: const EdgeInsets.fromLTRB(25, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 1, - initialValue: _columnSpacing, - onChanged: (double val) { - setState(() { - _columnSpacing = val; - }); - }, - step: 0.1, - loop: true, - padding: 5.0, - iconColor: model.textColor, - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text('Spacing ', style: TextStyle(color: model.textColor)), + CustomDirectionalButtons( + maxValue: 1, + initialValue: _columnSpacing, + onChanged: (double val) { + setState(() { + _columnSpacing = val; + }); + }, + step: 0.1, + loop: true, + padding: 5.0, + iconColor: model.textColor, + style: TextStyle(fontSize: 16.0, color: model.textColor), ), ], ), diff --git a/lib/samples/chart/cartesian_charts/chart_types/column/column_with_axis_base.dart b/lib/samples/chart/cartesian_charts/chart_types/column/column_with_axis_base.dart index 7f19d938..4b22b95d 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/column/column_with_axis_base.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/column/column_with_axis_base.dart @@ -88,33 +88,26 @@ class _AxisCrossingBaseValueState extends SampleViewState { return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Axis base value ', style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Container( - padding: const EdgeInsets.fromLTRB(20, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - underline: Container(color: const Color(0xFFBDBDBD), height: 1), - value: _selectedAxis, - items: _axis!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : '-2 (modified)', - child: Text( - value, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _onAxisTypeChange(value.toString()); - stateSetter(() {}); - }, - ), + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + underline: Container(color: const Color(0xFFBDBDBD), height: 1), + value: _selectedAxis, + items: _axis!.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : '-2 (modified)', + child: Text(value, style: TextStyle(color: model.textColor)), + ); + }).toList(), + onChanged: (dynamic value) { + _onAxisTypeChange(value.toString()); + stateSetter(() {}); + }, ), ], ); diff --git a/lib/samples/chart/cartesian_charts/chart_types/financial_charts/candle_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/financial_charts/candle_chart.dart index 6d120b04..e25bc25b 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/financial_charts/candle_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/financial_charts/candle_chart.dart @@ -337,6 +337,7 @@ class _CandleChartState extends SampleViewState { Widget _buildEnableSolidCandlesRow(StateSetter stateSetter) { return SizedBox( child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Enable solid candles', @@ -364,6 +365,7 @@ class _CandleChartState extends SampleViewState { Widget _buildShowIndicationRow(StateSetter stateSetter) { return SizedBox( child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Show indication for \nsame values', @@ -390,27 +392,24 @@ class _CandleChartState extends SampleViewState { // Method to build the row for setting width. Widget _buildWidthRow() { return Row( - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Padding( padding: const EdgeInsets.fromLTRB(0, 15, 0, 0), child: Text('Width ', style: TextStyle(color: model.textColor)), ), - Container( - padding: const EdgeInsets.fromLTRB(95, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 1, - initialValue: _width, - onChanged: (double val) { - setState(() { - _width = val; - }); - }, - step: 0.1, - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + CustomDirectionalButtons( + maxValue: 1, + initialValue: _width, + onChanged: (double val) { + setState(() { + _width = val; + }); + }, + step: 0.1, + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 16.0, color: model.textColor), ), ], ); @@ -419,28 +418,25 @@ class _CandleChartState extends SampleViewState { // Method to build the row for setting spacing. Widget _buildSpacingRow() { return Row( - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Padding( padding: const EdgeInsets.fromLTRB(0, 15, 0, 0), child: Text('Spacing ', style: TextStyle(color: model.textColor)), ), - Container( - padding: const EdgeInsets.fromLTRB(85, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 1, - initialValue: _space, - onChanged: (double val) { - setState(() { - _space = val; - }); - }, - step: 0.1, - loop: true, - padding: 5.0, - iconColor: model.textColor, - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + CustomDirectionalButtons( + maxValue: 1, + initialValue: _space, + onChanged: (double val) { + setState(() { + _space = val; + }); + }, + step: 0.1, + loop: true, + padding: 5.0, + iconColor: model.textColor, + style: TextStyle(fontSize: 16.0, color: model.textColor), ), ], ); @@ -449,7 +445,7 @@ class _CandleChartState extends SampleViewState { // Method to build the row for setting border radius. Widget _buildBorderRadiusRow() { return Row( - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Padding( padding: const EdgeInsets.fromLTRB(0, 15, 0, 0), @@ -458,21 +454,18 @@ class _CandleChartState extends SampleViewState { style: TextStyle(color: model.textColor), ), ), - Container( - padding: const EdgeInsets.fromLTRB(55, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 10, - initialValue: _borderRadius, - onChanged: (double val) { - setState(() { - _borderRadius = val; - }); - }, - loop: true, - padding: 5.0, - iconColor: model.textColor, - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + CustomDirectionalButtons( + maxValue: 10, + initialValue: _borderRadius, + onChanged: (double val) { + setState(() { + _borderRadius = val; + }); + }, + loop: true, + padding: 5.0, + iconColor: model.textColor, + style: TextStyle(fontSize: 16.0, color: model.textColor), ), ], ); diff --git a/lib/samples/chart/cartesian_charts/chart_types/histogram.dart b/lib/samples/chart/cartesian_charts/chart_types/histogram.dart index e07a6dd4..3b245af0 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/histogram.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/histogram.dart @@ -138,26 +138,21 @@ class _HistogramDefaultState extends SampleViewState { return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - 'Show distribution line ', + 'Show distribution line', style: TextStyle(color: model.textColor, fontSize: 16), ), - Padding( - padding: const EdgeInsets.all(8.0), - child: SizedBox( - width: 90, - child: CheckboxListTile( - activeColor: model.primaryColor, - value: _showDistributionCurve, - onChanged: (bool? value) { - setState(() { - _showDistributionCurve = value!; - stateSetter(() {}); - }); - }, - ), - ), + Checkbox( + activeColor: model.primaryColor, + value: _showDistributionCurve, + onChanged: (bool? value) { + setState(() { + _showDistributionCurve = value!; + stateSetter(() {}); + }); + }, ), ], ); diff --git a/lib/samples/chart/cartesian_charts/chart_types/line/animation_line_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/line/animation_line_chart.dart index 77f568a9..fbee6307 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/line/animation_line_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/line/animation_line_chart.dart @@ -63,7 +63,7 @@ class _AnimationLineDefaultState extends SampleViewState { } int _createRandomInt(int min, int max) { - final Random random = Random(); + final Random random = Random.secure(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/line/customized_line_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/line/customized_line_chart.dart index 8be0b077..3a73958e 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/line/customized_line_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/line/customized_line_chart.dart @@ -133,7 +133,7 @@ class _CustomLineSeriesRenderer extends LineSeriesRenderer { _CustomLineSeriesRenderer(this.series); final LineSeries series; - static Random randomNumber = Random(); + static Random randomNumber = Random.secure(); @override LineSegment createSegment() { diff --git a/lib/samples/chart/cartesian_charts/chart_types/range_area.dart b/lib/samples/chart/cartesian_charts/chart_types/range_area.dart index c07be8d1..2118b67b 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/range_area.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/range_area.dart @@ -92,10 +92,10 @@ class _RangeAreaState extends SampleViewState { chartData = []; double value = 15; for (int i = 0; i < 100; i++) { - final Random yValue = Random(); + final Random yValue = Random.secure(); (yValue.nextDouble() > .5) - ? value += Random().nextDouble() - : value -= Random().nextDouble(); + ? value += Random.secure().nextDouble() + : value -= Random.secure().nextDouble(); chartData.add( ChartSampleData( diff --git a/lib/samples/chart/cartesian_charts/chart_types/range_column/animation_range_column_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/range_column/animation_range_column_chart.dart index af7343e0..ea5943e3 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/range_column/animation_range_column_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/range_column/animation_range_column_chart.dart @@ -67,7 +67,7 @@ class _AnimationRangeColumnDefaultState extends SampleViewState { } int _buildRandomInt(int min, int max) { - final Random random = Random(); + final Random random = Random.secure(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/scatter/animation_scatter_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/scatter/animation_scatter_chart.dart index 13fc7a9f..578d94b7 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/scatter/animation_scatter_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/scatter/animation_scatter_chart.dart @@ -67,7 +67,7 @@ class _AnimationScatterDefaultState extends SampleViewState { } int _buildRandomInt(int min, int max) { - final Random random = Random(); + final Random random = Random.secure(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/spline/animation_spline_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/spline/animation_spline_chart.dart index efe0aa3b..65268662 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/spline/animation_spline_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/spline/animation_spline_chart.dart @@ -65,7 +65,7 @@ class _AnimationSplineDefaultState extends SampleViewState { /// Get the random value. int _buildRandomInt(int min, int max) { - final Random random = Random(); + final Random random = Random.secure(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/chart_types/spline/customized_spline_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/spline/customized_spline_chart.dart index e6ec3c2c..340a3b25 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/spline/customized_spline_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/spline/customized_spline_chart.dart @@ -94,7 +94,7 @@ class _CustomSplineSeriesRenderer extends SplineSeriesRenderer { final SplineSeries series; - static Random randomNumber = Random(); + static Random randomNumber = Random.secure(); @override SplineSegment createSegment() { diff --git a/lib/samples/chart/cartesian_charts/chart_types/spline/spline_types.dart b/lib/samples/chart/cartesian_charts/chart_types/spline/spline_types.dart index cdfde55e..5379932e 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/spline/spline_types.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/spline/spline_types.dart @@ -119,6 +119,7 @@ class _SplineTypesState extends SampleViewState { primaryXAxis: const NumericAxis( majorGridLines: MajorGridLines(width: 0), interval: 1, + edgeLabelPlacement: EdgeLabelPlacement.shift, ), primaryYAxis: const NumericAxis( labelFormat: '{value}%', diff --git a/lib/samples/chart/cartesian_charts/chart_types/step_line/animation_step_line_chart.dart b/lib/samples/chart/cartesian_charts/chart_types/step_line/animation_step_line_chart.dart index 5482144b..4a5630dc 100644 --- a/lib/samples/chart/cartesian_charts/chart_types/step_line/animation_step_line_chart.dart +++ b/lib/samples/chart/cartesian_charts/chart_types/step_line/animation_step_line_chart.dart @@ -64,7 +64,7 @@ class _AnimationStepLineDefaultState extends SampleViewState { } int _buildRandomInt(int min, int max) { - final Random random = Random(); + final Random random = Random.secure(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/infinite_scrolling.dart b/lib/samples/chart/cartesian_charts/infinite_scrolling.dart index f8c387bf..ac3800aa 100644 --- a/lib/samples/chart/cartesian_charts/infinite_scrolling.dart +++ b/lib/samples/chart/cartesian_charts/infinite_scrolling.dart @@ -233,7 +233,7 @@ class _InfiniteScrollingState extends SampleViewState { } int _generateRandomInteger(int min, int max) { - final Random random = Random(); + final Random random = Random.secure(); final int result = min + random.nextInt(max - min); return result < 50 ? 95 : result; } diff --git a/lib/samples/chart/cartesian_charts/legend/legend_various_options.dart b/lib/samples/chart/cartesian_charts/legend/legend_various_options.dart index c39b7b82..dcc3a4d3 100644 --- a/lib/samples/chart/cartesian_charts/legend/legend_various_options.dart +++ b/lib/samples/chart/cartesian_charts/legend/legend_various_options.dart @@ -189,88 +189,80 @@ class _CartesianLegendOptionsState extends SampleViewState { children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, + spacing: 40, children: [ - Flexible( - child: Text( - 'Position', - softWrap: false, - style: TextStyle( - fontSize: 16, - color: model.textColor, - ), + Text( + 'Position', + softWrap: false, + style: TextStyle( + fontSize: 16, + color: model.textColor, ), ), Flexible( - child: SizedBox( - width: dropDownWidth, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - isExpanded: true, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _selectedPosition, - items: _positionList!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'auto', - child: Text( - value, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _onPositionTypeChange(value.toString()); - stateSetter(() {}); - }, + child: DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + isExpanded: true, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, ), + value: _selectedPosition, + items: _positionList!.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'auto', + child: Text( + value, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (dynamic value) { + _onPositionTypeChange(value.toString()); + stateSetter(() {}); + }, ), ), ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, + spacing: 30, children: [ - Flexible( - child: Text( - model.isWebFullView - ? 'Overflow \nmode' - : 'Overflow mode', - softWrap: false, - style: TextStyle( - fontSize: 16, - color: model.textColor, - ), + Text( + model.isWebFullView + ? 'Overflow \nmode' + : 'Overflow mode', + softWrap: false, + style: TextStyle( + fontSize: 16, + color: model.textColor, ), ), Flexible( - child: SizedBox( - width: dropDownWidth, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - isExpanded: true, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _selectedMode, - items: _modeList!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'wrap', - child: Text( - value, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _onModeTypeChange(value); - stateSetter(() {}); - }, + child: DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + isExpanded: true, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, ), + value: _selectedMode, + items: _modeList!.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'wrap', + child: Text( + value, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (dynamic value) { + _onModeTypeChange(value); + stateSetter(() {}); + }, ), ), ], diff --git a/lib/samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_points.dart b/lib/samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_points.dart index 069a56c9..f613edfc 100644 --- a/lib/samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_points.dart +++ b/lib/samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_points.dart @@ -179,7 +179,7 @@ class _LiveVerticalState extends SampleViewState { /// Generates a random integer within the specified range. int _generateRandomInt(int min, int max) { - final Random random = Random(); + final Random random = Random.secure(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_series.dart b/lib/samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_series.dart index 189f21b3..f17dd431 100644 --- a/lib/samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_series.dart +++ b/lib/samples/chart/cartesian_charts/real_time_charts/add_remove_data/add_remove_series.dart @@ -164,7 +164,7 @@ class _LiveVerticalState extends SampleViewState { /// Generates a random integer between the specified /// minimum and maximum values. int _generateRandomInteger(int min, int max) { - final Random random = Random(); + final Random random = Random.secure(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/real_time_charts/live_update/real_time_line_chart.dart b/lib/samples/chart/cartesian_charts/real_time_charts/live_update/real_time_line_chart.dart index 0a930673..91c74a63 100644 --- a/lib/samples/chart/cartesian_charts/real_time_charts/live_update/real_time_line_chart.dart +++ b/lib/samples/chart/cartesian_charts/real_time_charts/live_update/real_time_line_chart.dart @@ -115,7 +115,7 @@ class _LiveLineChartState extends SampleViewState { /// Generates a random integer within the specified range. int _generateRandomInteger(int min, int max) { - final math.Random random = math.Random(); + final math.Random random = math.Random.secure(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/real_time_charts/live_update/vertical_live_chart.dart b/lib/samples/chart/cartesian_charts/real_time_charts/live_update/vertical_live_chart.dart index 9e9c4cc3..2e26e268 100644 --- a/lib/samples/chart/cartesian_charts/real_time_charts/live_update/vertical_live_chart.dart +++ b/lib/samples/chart/cartesian_charts/real_time_charts/live_update/vertical_live_chart.dart @@ -103,7 +103,7 @@ class _LiveUpdateState extends SampleViewState { /// Generates a random integer between the specified range. int _generateRandomInteger(int min, int max) { - final Random random = Random(); + final Random random = Random.secure(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/real_time_charts/update_data_source.dart b/lib/samples/chart/cartesian_charts/real_time_charts/update_data_source.dart index d2fb4d25..8cbb2ad8 100644 --- a/lib/samples/chart/cartesian_charts/real_time_charts/update_data_source.dart +++ b/lib/samples/chart/cartesian_charts/real_time_charts/update_data_source.dart @@ -35,7 +35,7 @@ class _LiveVerticalState extends SampleViewState { ChartSampleData(x: 7, y: 30), ChartSampleData(x: 9, y: 72), ]; - _random = Random(); + _random = Random.secure(); super.initState(); } diff --git a/lib/samples/chart/cartesian_charts/series_features/data_label/default_data_labels.dart b/lib/samples/chart/cartesian_charts/series_features/data_label/default_data_labels.dart index d60afabc..6b220938 100644 --- a/lib/samples/chart/cartesian_charts/series_features/data_label/default_data_labels.dart +++ b/lib/samples/chart/cartesian_charts/series_features/data_label/default_data_labels.dart @@ -81,25 +81,23 @@ class _DataLabelDefaultState extends SampleViewState { /// Builds the checkbox for using series color. Widget buildSeriesColorCheckbox(StateSetter stateSetter) { return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Use series color', style: TextStyle(color: model.textColor, fontSize: 16), ), - Padding( - padding: const EdgeInsets.fromLTRB(8, 0, 0, 0), - child: SizedBox( - width: 90, - child: CheckboxListTile( - activeColor: model.primaryColor, - value: _useSeriesColor, - onChanged: (bool? value) { - setState(() { - _useSeriesColor = value!; - stateSetter(() {}); - }); - }, - ), + SizedBox( + width: 90, + child: CheckboxListTile( + activeColor: model.primaryColor, + value: _useSeriesColor, + onChanged: (bool? value) { + setState(() { + _useSeriesColor = value!; + stateSetter(() {}); + }); + }, ), ), ], @@ -109,31 +107,27 @@ class _DataLabelDefaultState extends SampleViewState { /// Builds the dropdown for label alignment settings. Widget buildLabelAlignmentDropdown(StateSetter stateSetter) { return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Label alignment', style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Container( - padding: const EdgeInsets.fromLTRB(52, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container(color: const Color(0xFFBDBDBD), height: 1), - value: _labelAlignment, - items: _chartAlign!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'center', - child: Text(value, style: TextStyle(color: model.textColor)), - ); - }).toList(), - onChanged: (dynamic value) { - _onAlignmentChange(value.toString()); - stateSetter(() {}); - }, - ), + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container(color: const Color(0xFFBDBDBD), height: 1), + value: _labelAlignment, + items: _chartAlign!.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'center', + child: Text(value, style: TextStyle(color: model.textColor)), + ); + }).toList(), + onChanged: (dynamic value) { + _onAlignmentChange(value.toString()); + stateSetter(() {}); + }, ), ], ); @@ -142,31 +136,27 @@ class _DataLabelDefaultState extends SampleViewState { /// Builds the dropdown for label position settings. Widget buildLabelPositionDropdown(StateSetter stateSetter) { return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Label position', style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Container( - padding: const EdgeInsets.fromLTRB(67, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container(color: const Color(0xFFBDBDBD), height: 1), - value: _labelPosition, - items: _positionType!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'top', - child: Text(value, style: TextStyle(color: model.textColor)), - ); - }).toList(), - onChanged: (dynamic value) { - _onPositionChange(value.toString()); - stateSetter(() {}); - }, - ), + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container(color: const Color(0xFFBDBDBD), height: 1), + value: _labelPosition, + items: _positionType!.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'top', + child: Text(value, style: TextStyle(color: model.textColor)), + ); + }).toList(), + onChanged: (dynamic value) { + _onPositionChange(value.toString()); + stateSetter(() {}); + }, ), ], ); @@ -175,25 +165,25 @@ class _DataLabelDefaultState extends SampleViewState { /// Builds the slider for horizontal padding settings. Widget buildHorizontalPaddingSlider() { return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - 'Horizontal padding', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(10, 0, 0, 0), - child: CustomDirectionalButtons( - minValue: -50, - maxValue: 50, - initialValue: _horizontalPadding, - onChanged: (double value) => setState(() { - _horizontalPadding = value; - }), - step: 10, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), + Flexible( + child: Text( + 'Horizontal padding', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), ), + CustomDirectionalButtons( + minValue: -50, + maxValue: 50, + initialValue: _horizontalPadding, + onChanged: (double value) => setState(() { + _horizontalPadding = value; + }), + step: 10, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ], ); } @@ -201,24 +191,22 @@ class _DataLabelDefaultState extends SampleViewState { /// Builds the slider for vertical padding settings. Widget buildVerticalPaddingSlider() { return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Vertical padding', style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Container( - padding: const EdgeInsets.fromLTRB(28, 0, 0, 0), - child: CustomDirectionalButtons( - minValue: -50, - maxValue: 50, - initialValue: _verticalPadding, - onChanged: (double val) => setState(() { - _verticalPadding = val; - }), - step: 10, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), + CustomDirectionalButtons( + minValue: -50, + maxValue: 50, + initialValue: _verticalPadding, + onChanged: (double val) => setState(() { + _verticalPadding = val; + }), + step: 10, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), ), ], ); diff --git a/lib/samples/chart/cartesian_charts/series_features/sorting.dart b/lib/samples/chart/cartesian_charts/series_features/sorting.dart index b0186f63..36d183ad 100644 --- a/lib/samples/chart/cartesian_charts/series_features/sorting.dart +++ b/lib/samples/chart/cartesian_charts/series_features/sorting.dart @@ -74,31 +74,24 @@ class _SortingDefaultState extends SampleViewState { /// Builds the dropdown for sorting options. Widget _buildSortByDropdown(StateSetter stateSetter) { return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - 'Sort by ', - style: TextStyle(color: model.textColor, fontSize: 16), - ), - Container( - padding: const EdgeInsets.fromLTRB(50, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container(color: const Color(0xFFBDBDBD), height: 1), - value: _selectedType, - items: _labelList!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'y', - child: Text(value, style: TextStyle(color: model.textColor)), - ); - }).toList(), - onChanged: (dynamic value) { - _onPositionTypeChange(value.toString()); - stateSetter(() {}); - }, - ), + Text('Sort by', style: TextStyle(color: model.textColor, fontSize: 16)), + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container(color: const Color(0xFFBDBDBD), height: 1), + value: _selectedType, + items: _labelList!.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'y', + child: Text(value, style: TextStyle(color: model.textColor)), + ); + }).toList(), + onChanged: (dynamic value) { + _onPositionTypeChange(value.toString()); + stateSetter(() {}); + }, ), ], ); @@ -107,29 +100,27 @@ class _SortingDefaultState extends SampleViewState { /// Builds the dropdown for sorting order options. Widget _buildSortingOrderDropdown(StateSetter stateSetter) { return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - 'Sorting order ', + 'Sorting order', style: TextStyle(color: model.textColor, fontSize: 16), ), - SizedBox( - height: 50, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container(color: const Color(0xFFBDBDBD), height: 1), - value: _selectedSortType, - items: _sortList!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'none', - child: Text(value, style: TextStyle(color: model.textColor)), - ); - }).toList(), - onChanged: (dynamic value) { - _onSortingTypeChange(value.toString()); - stateSetter(() {}); - }, - ), + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container(color: const Color(0xFFBDBDBD), height: 1), + value: _selectedSortType, + items: _sortList!.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'none', + child: Text(value, style: TextStyle(color: model.textColor)), + ); + }).toList(), + onChanged: (dynamic value) { + _onSortingTypeChange(value.toString()); + stateSetter(() {}); + }, ), ], ); diff --git a/lib/samples/chart/cartesian_charts/trendline/default_trendline.dart b/lib/samples/chart/cartesian_charts/trendline/default_trendline.dart index 6b7351c5..ee311270 100644 --- a/lib/samples/chart/cartesian_charts/trendline/default_trendline.dart +++ b/lib/samples/chart/cartesian_charts/trendline/default_trendline.dart @@ -85,24 +85,22 @@ class _TrendLineDefaultState extends SampleViewState { ? 245 : MediaQuery.of(context).size.width; final double dropDownWidth = - (model.isWebFullView ? 0.76 : 0.57) * screenWidth; + (model.isWebFullView ? 0.72 : 0.57) * screenWidth; return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return ListView( shrinkWrap: true, children: [ Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Padding( - padding: const EdgeInsets.fromLTRB(0, 15, 0, 0), - child: Text( - 'Trendline \ntype', - style: TextStyle(color: model.textColor), - ), + Text( + 'Trendline \ntype', + style: TextStyle(color: model.textColor), ), Container( padding: EdgeInsets.fromLTRB( - model.isWebFullView ? 50 : 70, + model.isWebFullView ? 30 : 70, 0, 0, 0, diff --git a/lib/samples/chart/cartesian_charts/trendline/trendline_forecast.dart b/lib/samples/chart/cartesian_charts/trendline/trendline_forecast.dart index a591e1d7..72a5a0ee 100644 --- a/lib/samples/chart/cartesian_charts/trendline/trendline_forecast.dart +++ b/lib/samples/chart/cartesian_charts/trendline/trendline_forecast.dart @@ -80,45 +80,45 @@ class _TrendLineForecastState extends SampleViewState { shrinkWrap: true, children: [ Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - 'Forward forecast', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(30, 0, 20, 0), - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _forwardForecastValue, - onChanged: (double val) => setState(() { - _forwardForecastValue = val; - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), + Flexible( + child: Text( + 'Forward forecast', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), ), + CustomDirectionalButtons( + maxValue: 50, + initialValue: _forwardForecastValue, + onChanged: (double val) => setState(() { + _forwardForecastValue = val; + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - 'Backward forecast', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), - Container( - padding: const EdgeInsets.fromLTRB(20, 0, 20, 0), - child: CustomDirectionalButtons( - maxValue: 50, - initialValue: _backwardForecastValue, - onChanged: (double val) => setState(() { - _backwardForecastValue = val; - }), - loop: true, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), + Flexible( + child: Text( + 'Backward forecast', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), ), + CustomDirectionalButtons( + maxValue: 50, + initialValue: _backwardForecastValue, + onChanged: (double val) => setState(() { + _backwardForecastValue = val; + }), + loop: true, + iconColor: model.textColor, + style: TextStyle(fontSize: 20.0, color: model.textColor), + ), ], ), ], diff --git a/lib/samples/chart/cartesian_charts/user_interactions/auto_scrolling.dart b/lib/samples/chart/cartesian_charts/user_interactions/auto_scrolling.dart index 80dfd2a3..ec29278d 100644 --- a/lib/samples/chart/cartesian_charts/user_interactions/auto_scrolling.dart +++ b/lib/samples/chart/cartesian_charts/user_interactions/auto_scrolling.dart @@ -173,7 +173,7 @@ class _AutoScrollingChartState extends SampleViewState { } int _generateRandomInt(int min, int max) { - final math.Random random = math.Random(); + final math.Random random = math.Random.secure(); return min + random.nextInt(max - min); } diff --git a/lib/samples/chart/cartesian_charts/user_interactions/crosshair.dart b/lib/samples/chart/cartesian_charts/user_interactions/crosshair.dart index a61acd66..509f5f1f 100644 --- a/lib/samples/chart/cartesian_charts/user_interactions/crosshair.dart +++ b/lib/samples/chart/cartesian_charts/user_interactions/crosshair.dart @@ -238,7 +238,7 @@ class _DefaultCrossHairState extends SampleViewState { /// Method to get random data points for the chart with crosshair sample. List _buildChartData() { final List randomData = []; - final Random rand = Random(); + final Random rand = Random.secure(); double value = 100; for (int i = 1; i < 2000; i++) { if (rand.nextDouble() > 0.5) { diff --git a/lib/samples/chart/circular_charts/chart_types/doughnut/semi_doughnut_chart.dart b/lib/samples/chart/circular_charts/chart_types/doughnut/semi_doughnut_chart.dart index 508bf5f0..a0f5e233 100644 --- a/lib/samples/chart/circular_charts/chart_types/doughnut/semi_doughnut_chart.dart +++ b/lib/samples/chart/circular_charts/chart_types/doughnut/semi_doughnut_chart.dart @@ -49,6 +49,7 @@ class _SemiDoughnutChartState extends SampleViewState { /// Builds the start angle adjustment setting. Widget _buildStartAngleSetting() { return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Start angle ', @@ -75,7 +76,7 @@ class _SemiDoughnutChartState extends SampleViewState { /// Builds the end angle adjustment setting. Widget _buildEndAngleSetting() { return Row( - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Padding( padding: const EdgeInsets.fromLTRB(0, 15, 0, 0), diff --git a/lib/samples/chart/circular_charts/chart_types/pie/pie_with_image.dart b/lib/samples/chart/circular_charts/chart_types/pie/pie_with_image.dart index ca153fe5..41b5c150 100644 --- a/lib/samples/chart/circular_charts/chart_types/pie/pie_with_image.dart +++ b/lib/samples/chart/circular_charts/chart_types/pie/pie_with_image.dart @@ -113,7 +113,7 @@ class _PieImageShaderState extends SampleViewState { image1!, TileMode.repeated, TileMode.repeated, - Matrix4.identity().scaled(0.5).storage, + Matrix4.identity().scaledByDouble(0.5, 0.5, 0.5, 1.0).storage, ), ), _ChartShaderData( @@ -124,7 +124,7 @@ class _PieImageShaderState extends SampleViewState { image2!, TileMode.repeated, TileMode.repeated, - Matrix4.identity().scaled(0.6).storage, + Matrix4.identity().scaledByDouble(0.6, 0.6, 0.6, 1.0).storage, ), ), _ChartShaderData( @@ -135,7 +135,7 @@ class _PieImageShaderState extends SampleViewState { image3!, TileMode.repeated, TileMode.repeated, - Matrix4.identity().scaled(0.6).storage, + Matrix4.identity().scaledByDouble(0.6, 0.6, 0.6, 1.0).storage, ), ), _ChartShaderData( @@ -146,7 +146,7 @@ class _PieImageShaderState extends SampleViewState { image4!, TileMode.repeated, TileMode.repeated, - Matrix4.identity().scaled(0.5).storage, + Matrix4.identity().scaledByDouble(0.5, 0.5, 0.5, 1.0).storage, ), ), ], diff --git a/lib/samples/chart/circular_charts/chart_types/pie/pie_with_smart_data_label.dart b/lib/samples/chart/circular_charts/chart_types/pie/pie_with_smart_data_label.dart index 5f78de3e..7e951b18 100644 --- a/lib/samples/chart/circular_charts/chart_types/pie/pie_with_smart_data_label.dart +++ b/lib/samples/chart/circular_charts/chart_types/pie/pie_with_smart_data_label.dart @@ -65,6 +65,7 @@ class _PieSmartDataLabelsState extends SampleViewState { shrinkWrap: true, children: [ Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Label intersect \naction', diff --git a/lib/samples/chart/circular_charts/chart_types/pie/point_render_mode.dart b/lib/samples/chart/circular_charts/chart_types/pie/point_render_mode.dart index 95a33c22..82205029 100644 --- a/lib/samples/chart/circular_charts/chart_types/pie/point_render_mode.dart +++ b/lib/samples/chart/circular_charts/chart_types/pie/point_render_mode.dart @@ -72,27 +72,24 @@ class _PiePointRenderModeState extends SampleViewState { double screenWidth, StateSetter stateSetter, ) { - return SizedBox( - height: 60, - child: ListView( - shrinkWrap: true, - physics: const ClampingScrollPhysics(), - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Text( - model.isWebFullView - ? 'Point \nrendering \nmode' - : 'Point rendering mode', - softWrap: false, - style: TextStyle(fontSize: 16, color: model.textColor), - ), - _buildPointRenderModeDropdown(screenWidth, stateSetter), - ], - ), - ], - ), + return ListView( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Text( + model.isWebFullView + ? 'Point \nrendering \nmode' + : 'Point rendering mode', + softWrap: false, + style: TextStyle(fontSize: 16, color: model.textColor), + ), + _buildPointRenderModeDropdown(screenWidth, stateSetter), + ], + ), + ], ); } @@ -101,28 +98,23 @@ class _PiePointRenderModeState extends SampleViewState { double screenWidth, StateSetter stateSetter, ) { - return Container( - padding: EdgeInsets.only(left: 0.07 * screenWidth), - width: 0.5 * screenWidth, - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container(color: const Color(0xFFBDBDBD), height: 1), - value: _selectedMode, - items: _modeList!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'Render mode', - child: Text(value, style: TextStyle(color: model.textColor)), - ); - }).toList(), - onChanged: (dynamic value) { - setState(() { - _onPointRenderModeChange(value); - stateSetter(() {}); - }); - }, - ), + return DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container(color: const Color(0xFFBDBDBD), height: 1), + value: _selectedMode, + items: _modeList!.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'Render mode', + child: Text(value, style: TextStyle(color: model.textColor)), + ); + }).toList(), + onChanged: (dynamic value) { + setState(() { + _onPointRenderModeChange(value); + stateSetter(() {}); + }); + }, ); } diff --git a/lib/samples/chart/circular_charts/chart_types/pie/semi_pie_chart.dart b/lib/samples/chart/circular_charts/chart_types/pie/semi_pie_chart.dart index 82b62dc6..8a86952f 100644 --- a/lib/samples/chart/circular_charts/chart_types/pie/semi_pie_chart.dart +++ b/lib/samples/chart/circular_charts/chart_types/pie/semi_pie_chart.dart @@ -55,24 +55,22 @@ class _SemiPieChartState extends SampleViewState { /// Creates a UI component for adjusting the starting angle of the chart. Widget _buildStartAngleSetting() { return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - 'Start angle ', + 'Start angle', style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Container( - padding: const EdgeInsets.fromLTRB(40, 0, 0, 0), - child: CustomDirectionalButtons( - minValue: 90, - maxValue: 270, - initialValue: _startAngle.toDouble(), - onChanged: (double val) => setState(() { - _startAngle = val.toInt(); - }), - step: 10, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), + CustomDirectionalButtons( + minValue: 90, + maxValue: 270, + initialValue: _startAngle.toDouble(), + onChanged: (double val) => setState(() { + _startAngle = val.toInt(); + }), + step: 10, + iconColor: model.textColor, + style: TextStyle(fontSize: 16.0, color: model.textColor), ), ], ); @@ -81,28 +79,22 @@ class _SemiPieChartState extends SampleViewState { /// Creates a UI component for adjusting the ending angle of the chart. Widget _buildEndAngleSetting() { return Row( - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Padding( - padding: const EdgeInsets.fromLTRB(0, 15, 0, 0), - child: Text( - 'End angle ', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'End angle', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Container( - padding: const EdgeInsets.fromLTRB(50, 0, 0, 0), - child: CustomDirectionalButtons( - minValue: 90, - maxValue: 270, - initialValue: _endAngle.toDouble(), - onChanged: (double val) => setState(() { - _endAngle = val.toInt(); - }), - step: 10, - iconColor: model.textColor, - style: TextStyle(fontSize: 20.0, color: model.textColor), - ), + CustomDirectionalButtons( + minValue: 90, + maxValue: 270, + initialValue: _endAngle.toDouble(), + onChanged: (double val) => setState(() { + _endAngle = val.toInt(); + }), + step: 10, + iconColor: model.textColor, + style: TextStyle(fontSize: 16.0, color: model.textColor), ), ], ); diff --git a/lib/samples/chart/circular_charts/legend/legend_with_various_options.dart b/lib/samples/chart/circular_charts/legend/legend_with_various_options.dart index affe0182..9847dab7 100644 --- a/lib/samples/chart/circular_charts/legend/legend_with_various_options.dart +++ b/lib/samples/chart/circular_charts/legend/legend_with_various_options.dart @@ -254,29 +254,21 @@ class _LegendOptionsState extends SampleViewState { style: TextStyle(fontSize: 16, color: model.textColor), ), ), - Flexible( - flex: 4, - child: Container( - padding: const EdgeInsets.fromLTRB(35, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: CustomDirectionalButtons( - minValue: -100, - maxValue: 100, - initialValue: _xOffset, - onChanged: (double val) => setState(() { - _xOffset = _enableFloatingLegend ? val : 0; - }), - step: _enableFloatingLegend ? 10 : 0, - iconColor: model.textColor.withValues( - alpha: _enableFloatingLegend ? 1 : 0.5, - ), - style: TextStyle( - fontSize: 16.0, - color: model.textColor.withValues( - alpha: _enableFloatingLegend ? 1 : 0.5, - ), - ), + CustomDirectionalButtons( + minValue: -100, + maxValue: 100, + initialValue: _xOffset, + onChanged: (double val) => setState(() { + _xOffset = _enableFloatingLegend ? val : 0; + }), + step: _enableFloatingLegend ? 10 : 0, + iconColor: model.textColor.withValues( + alpha: _enableFloatingLegend ? 1 : 0.5, + ), + style: TextStyle( + fontSize: 16.0, + color: model.textColor.withValues( + alpha: _enableFloatingLegend ? 1 : 0.5, ), ), ), @@ -297,29 +289,21 @@ class _LegendOptionsState extends SampleViewState { style: TextStyle(fontSize: 16, color: model.textColor), ), ), - Flexible( - flex: 4, - child: Container( - padding: const EdgeInsets.fromLTRB(35, 0, 0, 0), - height: 50, - alignment: Alignment.bottomLeft, - child: CustomDirectionalButtons( - minValue: -100, - maxValue: 100, - initialValue: _yOffset, - onChanged: (double val) => setState(() { - _yOffset = _enableFloatingLegend ? val : 0; - }), - step: _enableFloatingLegend ? 10 : 0, - iconColor: model.textColor.withValues( - alpha: _enableFloatingLegend ? 1 : 0.5, - ), - style: TextStyle( - fontSize: 16.0, - color: model.textColor.withValues( - alpha: _enableFloatingLegend ? 1 : 0.5, - ), - ), + CustomDirectionalButtons( + minValue: -100, + maxValue: 100, + initialValue: _yOffset, + onChanged: (double val) => setState(() { + _yOffset = _enableFloatingLegend ? val : 0; + }), + step: _enableFloatingLegend ? 10 : 0, + iconColor: model.textColor.withValues( + alpha: _enableFloatingLegend ? 1 : 0.5, + ), + style: TextStyle( + fontSize: 16.0, + color: model.textColor.withValues( + alpha: _enableFloatingLegend ? 1 : 0.5, ), ), ), diff --git a/lib/samples/chart/funnel_charts/default_funnel_chart.dart b/lib/samples/chart/funnel_charts/default_funnel_chart.dart index b6feeb0c..07acbd99 100644 --- a/lib/samples/chart/funnel_charts/default_funnel_chart.dart +++ b/lib/samples/chart/funnel_charts/default_funnel_chart.dart @@ -164,8 +164,7 @@ class _FunnelDefaultState extends SampleViewState { softWrap: false, style: TextStyle(fontSize: 16, color: model.textColor), ), - Container( - padding: EdgeInsets.only(left: 0.06 * screenWidth), + SizedBox( width: 0.5 * screenWidth, child: CheckboxListTile( controlAffinity: ListTileControlAffinity.leading, diff --git a/lib/samples/chart/funnel_charts/funnel_with_smart_labels.dart b/lib/samples/chart/funnel_charts/funnel_with_smart_labels.dart index 03aa1f24..5168910b 100644 --- a/lib/samples/chart/funnel_charts/funnel_with_smart_labels.dart +++ b/lib/samples/chart/funnel_charts/funnel_with_smart_labels.dart @@ -100,35 +100,30 @@ class _FunnelSmartLabelState extends SampleViewState { /// Builds the row for selecting the label position. Widget _buildLabelPositionRow(double dropDownWidth, StateSetter stateSetter) { return Row( + spacing: 20, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Flexible( - child: Text( - 'Label position', - softWrap: false, - style: TextStyle(fontSize: 16, color: model.textColor), - ), + Text( + 'Label position', + style: TextStyle(fontSize: 16, color: model.textColor), ), Flexible( - child: SizedBox( - width: dropDownWidth, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - isExpanded: true, - underline: Container(color: const Color(0xFFBDBDBD), height: 1), - value: _selectedPosition, - items: _labelPosition!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'outside', - child: Text(value, style: TextStyle(color: model.textColor)), - ); - }).toList(), - onChanged: (dynamic value) { - _onLabelPositionChange(value.toString()); - stateSetter(() {}); - }, - ), + child: DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + isExpanded: true, + underline: Container(color: const Color(0xFFBDBDBD), height: 1), + value: _selectedPosition, + items: _labelPosition!.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'outside', + child: Text(value, style: TextStyle(color: model.textColor)), + ); + }).toList(), + onChanged: (dynamic value) { + _onLabelPositionChange(value.toString()); + stateSetter(() {}); + }, ), ), ], @@ -138,46 +133,40 @@ class _FunnelSmartLabelState extends SampleViewState { /// Builds the row for selecting the overflow mode. Widget _buildOverflowModeRow(double dropDownWidth, StateSetter stateSetter) { return Row( + spacing: 20, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Flexible( - child: Text( - 'Overflow mode', - softWrap: false, - style: TextStyle( - fontSize: 16, - color: _selectedPosition != 'inside' - ? model.textColor.withValues(alpha: 0.3) - : model.textColor, - ), + Text( + 'Overflow mode', + style: TextStyle( + fontSize: 16, + color: _selectedPosition != 'inside' + ? model.textColor.withValues(alpha: 0.3) + : model.textColor, ), ), Flexible( - child: SizedBox( - height: 50, - width: dropDownWidth, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - isExpanded: true, - underline: Container(color: const Color(0xFFBDBDBD), height: 1), - value: _selectedOverflowMode, - items: _selectedPosition != 'inside' - ? null - : _overflowModeList!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'none', - child: Text( - value, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _updateOverflowMode(value.toString()); - stateSetter(() {}); - }, - ), + child: DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + isExpanded: true, + underline: Container(color: const Color(0xFFBDBDBD), height: 1), + value: _selectedOverflowMode, + items: _selectedPosition != 'inside' + ? null + : _overflowModeList!.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'none', + child: Text( + value, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (dynamic value) { + _updateOverflowMode(value.toString()); + stateSetter(() {}); + }, ), ), ], @@ -190,50 +179,44 @@ class _FunnelSmartLabelState extends SampleViewState { StateSetter stateSetter, ) { return Row( + spacing: 20, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Flexible( - child: Text( - 'Label intersect \naction', - softWrap: false, - style: TextStyle( - fontSize: 16, - color: - (_selectedOverflowMode != 'none' && - _selectedPosition != 'outside') - ? model.textColor.withValues(alpha: 0.3) - : model.textColor, - ), + Text( + 'Label intersect \naction', + style: TextStyle( + fontSize: 16, + color: + (_selectedOverflowMode != 'none' && + _selectedPosition != 'outside') + ? model.textColor.withValues(alpha: 0.3) + : model.textColor, ), ), Flexible( - child: SizedBox( - height: 50, - width: dropDownWidth, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - isExpanded: true, - underline: Container(color: const Color(0xFFBDBDBD), height: 1), - value: _labelIntersectAction, - items: - (_selectedOverflowMode != 'none' && - _selectedPosition != 'outside') - ? null - : _labelIntersectActionList!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'shift', - child: Text( - value, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _updateLabelIntersectAction(value.toString()); - stateSetter(() {}); - }, - ), + child: DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + isExpanded: true, + underline: Container(color: const Color(0xFFBDBDBD), height: 1), + value: _labelIntersectAction, + items: + (_selectedOverflowMode != 'none' && + _selectedPosition != 'outside') + ? null + : _labelIntersectActionList!.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'shift', + child: Text( + value, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (dynamic value) { + _updateLabelIntersectAction(value.toString()); + stateSetter(() {}); + }, ), ), ], diff --git a/lib/samples/chart/pyramid_charts/pyramid_with_smart_labels.dart b/lib/samples/chart/pyramid_charts/pyramid_with_smart_labels.dart index 21d13795..4e061956 100644 --- a/lib/samples/chart/pyramid_charts/pyramid_with_smart_labels.dart +++ b/lib/samples/chart/pyramid_charts/pyramid_with_smart_labels.dart @@ -150,33 +150,28 @@ class _PyramidSmartLabelState extends SampleViewState { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Flexible( - child: Text( - 'Label position', - softWrap: false, - style: TextStyle(fontSize: 16, color: model.textColor), - ), + Text( + 'Label position', + style: TextStyle(fontSize: 16, color: model.textColor), ), - Flexible( - child: SizedBox( - width: dropDownWidth, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - isExpanded: true, - underline: Container(color: const Color(0xFFBDBDBD), height: 1), - value: _selectedPosition, - items: _labelPosition!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'outside', - child: Text(value, style: TextStyle(color: model.textColor)), - ); - }).toList(), - onChanged: (dynamic value) { - _updateLabelPosition(value.toString()); - stateSetter(() {}); - }, - ), + SizedBox( + width: dropDownWidth, + child: DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + isExpanded: true, + underline: Container(color: const Color(0xFFBDBDBD), height: 1), + value: _selectedPosition, + items: _labelPosition!.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'outside', + child: Text(value, style: TextStyle(color: model.textColor)), + ); + }).toList(), + onChanged: (dynamic value) { + _updateLabelPosition(value.toString()); + stateSetter(() {}); + }, ), ), ], @@ -188,44 +183,39 @@ class _PyramidSmartLabelState extends SampleViewState { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Flexible( - child: Text( - 'Overflow mode', - softWrap: false, - style: TextStyle( - fontSize: 16, - color: _selectedPosition != 'inside' - ? model.textColor.withValues(alpha: 0.3) - : model.textColor, - ), + Text( + 'Overflow mode', + style: TextStyle( + fontSize: 16, + color: _selectedPosition != 'inside' + ? model.textColor.withValues(alpha: 0.3) + : model.textColor, ), ), - Flexible( - child: SizedBox( - height: 50, - width: dropDownWidth, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - isExpanded: true, - underline: Container(color: const Color(0xFFBDBDBD), height: 1), - value: _selectedOverflowMode, - items: _selectedPosition != 'inside' - ? null - : _overflowModeList!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'none', - child: Text( - value, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _updateOverflowMode(value.toString()); - stateSetter(() {}); - }, - ), + SizedBox( + height: 50, + width: dropDownWidth, + child: DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + isExpanded: true, + underline: Container(color: const Color(0xFFBDBDBD), height: 1), + value: _selectedOverflowMode, + items: _selectedPosition != 'inside' + ? null + : _overflowModeList!.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'none', + child: Text( + value, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (dynamic value) { + _updateOverflowMode(value.toString()); + stateSetter(() {}); + }, ), ), ], @@ -240,48 +230,43 @@ class _PyramidSmartLabelState extends SampleViewState { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Flexible( - child: Text( - 'Label intersect \naction', - softWrap: false, - style: TextStyle( - fontSize: 16, - color: - (_selectedOverflowMode != 'none' && - _selectedPosition != 'outside') - ? model.textColor.withValues(alpha: 0.3) - : model.textColor, - ), + Text( + 'Label intersect \naction', + style: TextStyle( + fontSize: 16, + color: + (_selectedOverflowMode != 'none' && + _selectedPosition != 'outside') + ? model.textColor.withValues(alpha: 0.3) + : model.textColor, ), ), - Flexible( - child: SizedBox( - height: 50, - width: dropDownWidth, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - isExpanded: true, - underline: Container(color: const Color(0xFFBDBDBD), height: 1), - value: _selectedIntersectAction, - items: - (_selectedOverflowMode != 'none' && - _selectedPosition != 'outside') - ? null - : _labelIntersectActionList!.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'shift', - child: Text( - value, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _updateLabelIntersectAction(value.toString()); - stateSetter(() {}); - }, - ), + SizedBox( + height: 50, + width: dropDownWidth, + child: DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + isExpanded: true, + underline: Container(color: const Color(0xFFBDBDBD), height: 1), + value: _selectedIntersectAction, + items: + (_selectedOverflowMode != 'none' && + _selectedPosition != 'outside') + ? null + : _labelIntersectActionList!.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'shift', + child: Text( + value, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (dynamic value) { + _updateLabelIntersectAction(value.toString()); + stateSetter(() {}); + }, ), ), ], diff --git a/lib/samples/datagrid/datagridsource/customer_datagridsource.dart b/lib/samples/datagrid/datagridsource/customer_datagridsource.dart index ba259610..25578eea 100644 --- a/lib/samples/datagrid/datagridsource/customer_datagridsource.dart +++ b/lib/samples/datagrid/datagridsource/customer_datagridsource.dart @@ -22,7 +22,7 @@ class CustomerDataGridSource extends DataGridSource { /// Determine to decide whether the platform is web or desktop. final bool isWebOrDesktop; - final math.Random _random = math.Random(); + final math.Random _random = math.Random.secure(); /// Instance of DataGridRow. List dataGridRows = []; diff --git a/lib/samples/datagrid/datagridsource/dealer_datagridsource.dart b/lib/samples/datagrid/datagridsource/dealer_datagridsource.dart index 9efa6a5d..80b9159e 100644 --- a/lib/samples/datagrid/datagridsource/dealer_datagridsource.dart +++ b/lib/samples/datagrid/datagridsource/dealer_datagridsource.dart @@ -48,7 +48,7 @@ class DealerDataGridSource extends DataGridSource { late TextStyle _textStyle; /// Help to generate the random number. - final Random _random = Random(); + final Random _random = Random.secure(); /// Help to control the editable text in [TextField] widget. final TextEditingController _editingController = TextEditingController(); diff --git a/lib/samples/datagrid/datagridsource/orderinfo_datagridsource.dart b/lib/samples/datagrid/datagridsource/orderinfo_datagridsource.dart index 64e3774c..0305252c 100644 --- a/lib/samples/datagrid/datagridsource/orderinfo_datagridsource.dart +++ b/lib/samples/datagrid/datagridsource/orderinfo_datagridsource.dart @@ -41,7 +41,7 @@ class OrderInfoDataGridSource extends DataGridSource { /// Get data count of an order. int? orderDataCount; - final math.Random _random = math.Random(); + final math.Random _random = math.Random.secure(); /// Instance of an order. List orders = []; diff --git a/lib/samples/datagrid/datagridsource/product_datagridsource.dart b/lib/samples/datagrid/datagridsource/product_datagridsource.dart index 523d2de2..f71dd7d0 100644 --- a/lib/samples/datagrid/datagridsource/product_datagridsource.dart +++ b/lib/samples/datagrid/datagridsource/product_datagridsource.dart @@ -25,7 +25,7 @@ class ProductDataGridSource extends DataGridSource { _buildDataGridRows(sampleType); } - final Random _random = Random(); + final Random _random = Random.secure(); /// Get data count of product. final int productDataCount; diff --git a/lib/samples/datagrid/datagridsource/realtime_datagridsource.dart b/lib/samples/datagrid/datagridsource/realtime_datagridsource.dart index 590d05f1..03662634 100644 --- a/lib/samples/datagrid/datagridsource/realtime_datagridsource.dart +++ b/lib/samples/datagrid/datagridsource/realtime_datagridsource.dart @@ -22,7 +22,7 @@ class RealTimeUpdateDataGridSource extends DataGridSource { /// Check whether the device is desktop or mobile platform. final bool isWebOrDesktop; - final math.Random _random = math.Random(); + final math.Random _random = math.Random.secure(); List _stocks = []; diff --git a/lib/samples/datagrid/datagridsource/stock_datagridsource.dart b/lib/samples/datagrid/datagridsource/stock_datagridsource.dart index 90a3d899..bfa9c634 100644 --- a/lib/samples/datagrid/datagridsource/stock_datagridsource.dart +++ b/lib/samples/datagrid/datagridsource/stock_datagridsource.dart @@ -19,7 +19,7 @@ class ConditionalStyleDataGridSource extends DataGridSource { _buildDataGridRows(); } - final math.Random _random = math.Random(); + final math.Random _random = math.Random.secure(); List _stocks = []; diff --git a/lib/samples/datagrid/datagridsource/stockinfo_datagridsource.dart b/lib/samples/datagrid/datagridsource/stockinfo_datagridsource.dart index 9977176e..b3912641 100644 --- a/lib/samples/datagrid/datagridsource/stockinfo_datagridsource.dart +++ b/lib/samples/datagrid/datagridsource/stockinfo_datagridsource.dart @@ -24,7 +24,7 @@ class StockInfoDataGridSource extends DataGridSource { /// Checks whether it's a grouping sample source or not. late bool isGroupingSample; - final math.Random _random = math.Random(); + final math.Random _random = math.Random.secure(); List _stocks = []; diff --git a/lib/samples/datagrid/datagridsource/team_datagridsource.dart b/lib/samples/datagrid/datagridsource/team_datagridsource.dart index 4b663b6b..5ac04e6a 100644 --- a/lib/samples/datagrid/datagridsource/team_datagridsource.dart +++ b/lib/samples/datagrid/datagridsource/team_datagridsource.dart @@ -229,7 +229,7 @@ class EmployeeDataGridSource extends DataGridSource { _buildDataGridRows(); } - final math.Random _random = math.Random(); + final math.Random _random = math.Random.secure(); List _dataGridRows = []; List _employees = []; diff --git a/lib/samples/date_picker/blackout_date_picker.dart b/lib/samples/date_picker/blackout_date_picker.dart index 66b2a2b1..f8fd577a 100644 --- a/lib/samples/date_picker/blackout_date_picker.dart +++ b/lib/samples/date_picker/blackout_date_picker.dart @@ -39,7 +39,7 @@ class _BlackoutDatePickerState extends SampleViewState { const Duration(days: 500), ); final DateTime endDate = DateTime.now().add(const Duration(days: 500)); - final Random random = Random(); + final Random random = Random.secure(); for ( DateTime date = startDate; date.isBefore(endDate); diff --git a/lib/samples/date_picker/customized_date_picker.dart b/lib/samples/date_picker/customized_date_picker.dart index 473f5381..b443fa3d 100644 --- a/lib/samples/date_picker/customized_date_picker.dart +++ b/lib/samples/date_picker/customized_date_picker.dart @@ -39,7 +39,7 @@ class _CustomizedDatePickerState extends SampleViewState { const Duration(days: 200), ); final DateTime endDate = DateTime.now().add(const Duration(days: 500)); - final Random random = Random(); + final Random random = Random.secure(); for ( DateTime date = startDate; date.isBefore(endDate); diff --git a/lib/samples/date_picker/date_picker_getting_started.dart b/lib/samples/date_picker/date_picker_getting_started.dart index c2fd5132..020ba863 100644 --- a/lib/samples/date_picker/date_picker_getting_started.dart +++ b/lib/samples/date_picker/date_picker_getting_started.dart @@ -309,41 +309,36 @@ class _GettingStartedDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: model.isWebFullView ? 4 : 5, - child: Text( - 'Picker view', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Picker view', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: model.isWebFullView ? 6 : 5, - child: Container( - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _viewModeString, - items: _viewModeList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'month', - child: Text( - value, - textAlign: TextAlign.center, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _onPickerViewChange(value); - stateSetter(() {}); - }, + Container( + alignment: Alignment.bottomLeft, + child: DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, ), + value: _viewModeString, + items: _viewModeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'month', + child: Text( + value, + textAlign: TextAlign.center, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (dynamic value) { + _onPickerViewChange(value); + stateSetter(() {}); + }, ), ), ], @@ -355,42 +350,39 @@ class _GettingStartedDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: model.isWebFullView ? 4 : 5, + Flexible( child: Text( 'Selection mode', style: TextStyle(fontSize: 16.0, color: model.textColor), ), ), - Expanded( - flex: model.isWebFullView ? 6 : 5, - child: Container( - padding: EdgeInsets.zero, - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _selectionModeString, - items: _selectionModeList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'extendableRange', - child: Text( - value, - textAlign: TextAlign.center, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _onSelectionModeChange(value); - stateSetter(() {}); - }, + Container( + padding: EdgeInsets.zero, + alignment: Alignment.bottomLeft, + child: DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, ), + value: _selectionModeString, + items: _selectionModeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'extendableRange', + child: Text( + value, + textAlign: TextAlign.center, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (dynamic value) { + _onSelectionModeChange(value); + stateSetter(() {}); + }, ), ), ], @@ -402,44 +394,39 @@ class _GettingStartedDatePickerState extends SampleViewState { ? SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: model.isWebFullView ? 4 : 5, - child: Text( - 'Selection Direction', - style: TextStyle( - fontSize: 16.0, - color: model.textColor, - ), + Text( + 'Selection Direction', + style: TextStyle( + fontSize: 16.0, + color: model.textColor, ), ), - Expanded( - flex: model.isWebFullView ? 6 : 5, - child: Container( - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _selectionDirectionString, - items: _selectionDirectionList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'both', - child: Text( - value, - textAlign: TextAlign.center, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _onSelectionDirectionChanged(value); - stateSetter(() {}); - }, + Container( + alignment: Alignment.bottomLeft, + child: DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, ), + value: _selectionDirectionString, + items: _selectionDirectionList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'both', + child: Text( + value, + textAlign: TextAlign.center, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (dynamic value) { + _onSelectionDirectionChanged(value); + stateSetter(() {}); + }, ), ), ], @@ -451,29 +438,24 @@ class _GettingStartedDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: model.isWebFullView ? 4 : 5, - child: Text( - 'Display date', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Display date', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: model.isWebFullView ? 6 : 5, - child: Container( - padding: EdgeInsets.zero, - alignment: Alignment.centerLeft, - child: Theme( - data: model.themeData.copyWith( - canvasColor: model.drawerBackgroundColor, - ), - child: _DateRangePickerOption( - _onDisplayDateChanged, - _controller.displayDate!, - model, - displayDate: _controller.displayDate!, - ), + Container( + padding: EdgeInsets.zero, + alignment: Alignment.centerLeft, + child: Theme( + data: model.themeData.copyWith( + canvasColor: model.drawerBackgroundColor, + ), + child: _DateRangePickerOption( + _onDisplayDateChanged, + _controller.displayDate!, + model, + displayDate: _controller.displayDate!, ), ), ), @@ -485,36 +467,31 @@ class _GettingStartedDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: 7, - child: Text( - 'Show action buttons', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Show action buttons', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: 3, - child: Container( - padding: EdgeInsets.zero, - child: Theme( - data: Theme.of( - context, - ).copyWith(canvasColor: model.drawerBackgroundColor), - child: Container( - alignment: Alignment.centerLeft, - child: Transform.scale( - scale: 0.8, - child: CupertinoSwitch( - value: _showActionButtons, - onChanged: (dynamic value) { - setState(() { - _onBoolValueChange('ShowActionButtons', value); - stateSetter(() {}); - }); - }, - activeTrackColor: model.primaryColor, - ), + Container( + padding: EdgeInsets.zero, + child: Theme( + data: Theme.of( + context, + ).copyWith(canvasColor: model.drawerBackgroundColor), + child: Container( + alignment: Alignment.centerLeft, + child: Transform.scale( + scale: 0.8, + child: CupertinoSwitch( + value: _showActionButtons, + onChanged: (dynamic value) { + setState(() { + _onBoolValueChange('ShowActionButtons', value); + stateSetter(() {}); + }); + }, + activeTrackColor: model.primaryColor, ), ), ), @@ -528,36 +505,31 @@ class _GettingStartedDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: 7, - child: Text( - 'Show today button', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Show today button', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: 3, - child: Container( - padding: EdgeInsets.zero, - child: Theme( - data: Theme.of( - context, - ).copyWith(canvasColor: model.drawerBackgroundColor), - child: Container( - alignment: Alignment.centerLeft, - child: Transform.scale( - scale: 0.8, - child: CupertinoSwitch( - value: _showTodayButton, - onChanged: (dynamic value) { - setState(() { - _onBoolValueChange('ShowTodayButton', value); - stateSetter(() {}); - }); - }, - activeTrackColor: model.primaryColor, - ), + Container( + padding: EdgeInsets.zero, + child: Theme( + data: Theme.of( + context, + ).copyWith(canvasColor: model.drawerBackgroundColor), + child: Container( + alignment: Alignment.centerLeft, + child: Transform.scale( + scale: 0.8, + child: CupertinoSwitch( + value: _showTodayButton, + onChanged: (dynamic value) { + setState(() { + _onBoolValueChange('ShowTodayButton', value); + stateSetter(() {}); + }); + }, + activeTrackColor: model.primaryColor, ), ), ), @@ -571,39 +543,31 @@ class _GettingStartedDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: 7, - child: Text( - 'Enable view navigation', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Enable view navigation', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: 3, - child: Container( - padding: EdgeInsets.zero, - child: Theme( - data: Theme.of( - context, - ).copyWith(canvasColor: model.drawerBackgroundColor), - child: Container( - alignment: Alignment.centerLeft, - child: Transform.scale( - scale: 0.8, - child: CupertinoSwitch( - value: _enableViewNavigation, - onChanged: (bool value) { - setState(() { - _onBoolValueChange( - 'EnableViewNavigation', - value, - ); - stateSetter(() {}); - }); - }, - activeTrackColor: model.primaryColor, - ), + Container( + padding: EdgeInsets.zero, + child: Theme( + data: Theme.of( + context, + ).copyWith(canvasColor: model.drawerBackgroundColor), + child: Container( + alignment: Alignment.centerLeft, + child: Transform.scale( + scale: 0.8, + child: CupertinoSwitch( + value: _enableViewNavigation, + onChanged: (bool value) { + setState(() { + _onBoolValueChange('EnableViewNavigation', value); + stateSetter(() {}); + }); + }, + activeTrackColor: model.primaryColor, ), ), ), @@ -617,34 +581,29 @@ class _GettingStartedDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: 7, - child: Text( - 'Enable past dates', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Enable past dates', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: 3, - child: Container( - padding: EdgeInsets.zero, - child: Theme( - data: Theme.of( - context, - ).copyWith(canvasColor: model.drawerBackgroundColor), - child: Container( - alignment: Alignment.centerLeft, - child: Transform.scale( - scale: 0.8, - child: CupertinoSwitch( - value: _enablePastDates, - onChanged: (dynamic value) { - _onBoolValueChange('EnablePastDates', value); - stateSetter(() {}); - }, - activeTrackColor: model.primaryColor, - ), + Container( + padding: EdgeInsets.zero, + child: Theme( + data: Theme.of( + context, + ).copyWith(canvasColor: model.drawerBackgroundColor), + child: Container( + alignment: Alignment.centerLeft, + child: Transform.scale( + scale: 0.8, + child: CupertinoSwitch( + value: _enablePastDates, + onChanged: (dynamic value) { + _onBoolValueChange('EnablePastDates', value); + stateSetter(() {}); + }, + activeTrackColor: model.primaryColor, ), ), ), @@ -658,39 +617,34 @@ class _GettingStartedDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: 7, - child: Text( - 'Enable swipe selection', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Enable swipe selection', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: 3, - child: Container( - padding: EdgeInsets.zero, - child: Theme( - data: Theme.of( - context, - ).copyWith(canvasColor: model.drawerBackgroundColor), - child: Container( - alignment: Alignment.centerLeft, - child: Transform.scale( - scale: 0.8, - child: CupertinoSwitch( - value: _enableSwipingSelection, - onChanged: (dynamic value) { - setState(() { - _onBoolValueChange( - 'EnableSwipingSelection', - value, - ); - stateSetter(() {}); - }); - }, - activeTrackColor: model.primaryColor, - ), + Container( + padding: EdgeInsets.zero, + child: Theme( + data: Theme.of( + context, + ).copyWith(canvasColor: model.drawerBackgroundColor), + child: Container( + alignment: Alignment.centerLeft, + child: Transform.scale( + scale: 0.8, + child: CupertinoSwitch( + value: _enableSwipingSelection, + onChanged: (dynamic value) { + setState(() { + _onBoolValueChange( + 'EnableSwipingSelection', + value, + ); + stateSetter(() {}); + }); + }, + activeTrackColor: model.primaryColor, ), ), ), @@ -704,36 +658,31 @@ class _GettingStartedDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: 7, - child: Text( - 'Show week number', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Show week number', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: 3, - child: Container( - padding: EdgeInsets.zero, - child: Theme( - data: Theme.of( - context, - ).copyWith(canvasColor: model.drawerBackgroundColor), - child: Container( - alignment: Alignment.centerLeft, - child: Transform.scale( - scale: 0.8, - child: CupertinoSwitch( - value: _showWeekNumber, - onChanged: (dynamic value) { - setState(() { - _onBoolValueChange('ShowWeekNumber', value); - stateSetter(() {}); - }); - }, - activeTrackColor: model.primaryColor, - ), + Container( + padding: EdgeInsets.zero, + child: Theme( + data: Theme.of( + context, + ).copyWith(canvasColor: model.drawerBackgroundColor), + child: Container( + alignment: Alignment.centerLeft, + child: Transform.scale( + scale: 0.8, + child: CupertinoSwitch( + value: _showWeekNumber, + onChanged: (dynamic value) { + setState(() { + _onBoolValueChange('ShowWeekNumber', value); + stateSetter(() {}); + }); + }, + activeTrackColor: model.primaryColor, ), ), ), @@ -747,37 +696,34 @@ class _GettingStartedDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: 7, + Flexible( child: Text( 'Show trailing and leading dates', style: TextStyle(fontSize: 16.0, color: model.textColor), ), ), - Expanded( - flex: 3, - child: Container( - padding: EdgeInsets.zero, - child: Theme( - data: Theme.of( - context, - ).copyWith(canvasColor: model.drawerBackgroundColor), - child: Container( - alignment: Alignment.centerLeft, - child: Transform.scale( - scale: 0.8, - child: CupertinoSwitch( - value: _showTrailingAndLeadingDates, - onChanged: (dynamic value) { - _onBoolValueChange( - 'ShowLeadingTrailingDates', - value, - ); - stateSetter(() {}); - }, - activeTrackColor: model.primaryColor, - ), + Container( + padding: EdgeInsets.zero, + child: Theme( + data: Theme.of( + context, + ).copyWith(canvasColor: model.drawerBackgroundColor), + child: Container( + alignment: Alignment.centerLeft, + child: Transform.scale( + scale: 0.8, + child: CupertinoSwitch( + value: _showTrailingAndLeadingDates, + onChanged: (dynamic value) { + _onBoolValueChange( + 'ShowLeadingTrailingDates', + value, + ); + stateSetter(() {}); + }, + activeTrackColor: model.primaryColor, ), ), ), diff --git a/lib/samples/date_picker/hijri_calendar.dart b/lib/samples/date_picker/hijri_calendar.dart index 57ef22dc..5d76a7cc 100644 --- a/lib/samples/date_picker/hijri_calendar.dart +++ b/lib/samples/date_picker/hijri_calendar.dart @@ -303,42 +303,34 @@ class _HijriDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: model.isWebFullView ? 4 : 5, - child: Text( - 'Picker view', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Picker view', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: model.isWebFullView ? 6 : 5, - child: Container( - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _viewModeString, - items: _viewModeList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'month', - child: Text( - value, - textAlign: TextAlign.center, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _onPickerViewChange(value); - stateSetter(() {}); - }, - ), + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, ), + value: _viewModeString, + items: _viewModeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'month', + child: Text( + value, + textAlign: TextAlign.center, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (dynamic value) { + _onPickerViewChange(value); + stateSetter(() {}); + }, ), ], ), @@ -349,43 +341,36 @@ class _HijriDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: model.isWebFullView ? 4 : 5, + Flexible( child: Text( 'Selection mode', style: TextStyle(fontSize: 16.0, color: model.textColor), ), ), - Expanded( - flex: model.isWebFullView ? 6 : 5, - child: Container( - padding: EdgeInsets.zero, - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _selectionModeString, - items: _selectionModeList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'extendableRange', - child: Text( - value, - textAlign: TextAlign.center, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _onSelectionModeChange(value); - stateSetter(() {}); - }, - ), + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, ), + value: _selectionModeString, + items: _selectionModeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'extendableRange', + child: Text( + value, + textAlign: TextAlign.center, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (dynamic value) { + _onSelectionModeChange(value); + stateSetter(() {}); + }, ), ], ), @@ -396,45 +381,37 @@ class _HijriDatePickerState extends SampleViewState { ? SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: model.isWebFullView ? 4 : 5, - child: Text( - 'Selection Direction', - style: TextStyle( - fontSize: 16.0, - color: model.textColor, - ), + Text( + 'Selection Direction', + style: TextStyle( + fontSize: 16.0, + color: model.textColor, ), ), - Expanded( - flex: model.isWebFullView ? 6 : 5, - child: Container( - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _selectionDirectionString, - items: _selectionDirectionList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'both', - child: Text( - value, - textAlign: TextAlign.center, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _onSelectionDirectionChanged(value); - stateSetter(() {}); - }, - ), + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, ), + value: _selectionDirectionString, + items: _selectionDirectionList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'both', + child: Text( + value, + textAlign: TextAlign.center, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (dynamic value) { + _onSelectionDirectionChanged(value); + stateSetter(() {}); + }, ), ], ), @@ -445,30 +422,21 @@ class _HijriDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: model.isWebFullView ? 4 : 5, - child: Text( - 'Display date', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Display date', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: model.isWebFullView ? 6 : 5, - child: Container( - padding: EdgeInsets.zero, - alignment: Alignment.centerLeft, - child: Theme( - data: model.themeData.copyWith( - canvasColor: model.drawerBackgroundColor, - ), - child: _DateRangePickerOption( - _onDisplayDateChanged, - _controller.displayDate!, - model, - displayDate: _controller.displayDate!, - ), - ), + Theme( + data: model.themeData.copyWith( + canvasColor: model.drawerBackgroundColor, + ), + child: _DateRangePickerOption( + _onDisplayDateChanged, + _controller.displayDate!, + model, + displayDate: _controller.displayDate!, ), ), ], @@ -479,38 +447,27 @@ class _HijriDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: 7, - child: Text( - 'Show action buttons', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Show action buttons', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: 3, - child: Container( - padding: EdgeInsets.zero, - child: Theme( - data: Theme.of( - context, - ).copyWith(canvasColor: model.drawerBackgroundColor), - child: Container( - alignment: Alignment.centerLeft, - child: Transform.scale( - scale: 0.8, - child: CupertinoSwitch( - value: _showActionButtons, - onChanged: (bool value) { - setState(() { - _onBoolValueChange('ShowActionButtons', value); - stateSetter(() {}); - }); - }, - activeTrackColor: model.primaryColor, - ), - ), - ), + Theme( + data: Theme.of( + context, + ).copyWith(canvasColor: model.drawerBackgroundColor), + child: Transform.scale( + scale: 0.8, + child: CupertinoSwitch( + value: _showActionButtons, + onChanged: (bool value) { + setState(() { + _onBoolValueChange('ShowActionButtons', value); + stateSetter(() {}); + }); + }, + activeTrackColor: model.primaryColor, ), ), ), @@ -522,38 +479,27 @@ class _HijriDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: 7, - child: Text( - 'Show today button', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Show today button', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: 3, - child: Container( - padding: EdgeInsets.zero, - child: Theme( - data: Theme.of( - context, - ).copyWith(canvasColor: model.drawerBackgroundColor), - child: Container( - alignment: Alignment.centerLeft, - child: Transform.scale( - scale: 0.8, - child: CupertinoSwitch( - value: _showTodayButton, - onChanged: (bool value) { - setState(() { - _onBoolValueChange('ShowTodayButton', value); - stateSetter(() {}); - }); - }, - activeTrackColor: model.primaryColor, - ), - ), - ), + Theme( + data: Theme.of( + context, + ).copyWith(canvasColor: model.drawerBackgroundColor), + child: Transform.scale( + scale: 0.8, + child: CupertinoSwitch( + value: _showTodayButton, + onChanged: (bool value) { + setState(() { + _onBoolValueChange('ShowTodayButton', value); + stateSetter(() {}); + }); + }, + activeTrackColor: model.primaryColor, ), ), ), @@ -565,41 +511,27 @@ class _HijriDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: 7, - child: Text( - 'Enable view navigation', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Enable view navigation', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: 3, - child: Container( - padding: EdgeInsets.zero, - child: Theme( - data: Theme.of( - context, - ).copyWith(canvasColor: model.drawerBackgroundColor), - child: Container( - alignment: Alignment.centerLeft, - child: Transform.scale( - scale: 0.8, - child: CupertinoSwitch( - value: _enableViewNavigation, - onChanged: (bool value) { - setState(() { - _onBoolValueChange( - 'EnableViewNavigation', - value, - ); - stateSetter(() {}); - }); - }, - activeTrackColor: model.primaryColor, - ), - ), - ), + Theme( + data: Theme.of( + context, + ).copyWith(canvasColor: model.drawerBackgroundColor), + child: Transform.scale( + scale: 0.8, + child: CupertinoSwitch( + value: _enableViewNavigation, + onChanged: (bool value) { + setState(() { + _onBoolValueChange('EnableViewNavigation', value); + stateSetter(() {}); + }); + }, + activeTrackColor: model.primaryColor, ), ), ), @@ -611,36 +543,25 @@ class _HijriDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: 7, - child: Text( - 'Enable past dates', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Enable past dates', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: 3, - child: Container( - padding: EdgeInsets.zero, - child: Theme( - data: Theme.of( - context, - ).copyWith(canvasColor: model.drawerBackgroundColor), - child: Container( - alignment: Alignment.centerLeft, - child: Transform.scale( - scale: 0.8, - child: CupertinoSwitch( - value: _enablePastDates, - onChanged: (dynamic value) { - _onBoolValueChange('EnablePastDates', value); - stateSetter(() {}); - }, - activeTrackColor: model.primaryColor, - ), - ), - ), + Theme( + data: Theme.of( + context, + ).copyWith(canvasColor: model.drawerBackgroundColor), + child: Transform.scale( + scale: 0.8, + child: CupertinoSwitch( + value: _enablePastDates, + onChanged: (dynamic value) { + _onBoolValueChange('EnablePastDates', value); + stateSetter(() {}); + }, + activeTrackColor: model.primaryColor, ), ), ), @@ -652,41 +573,27 @@ class _HijriDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: 7, - child: Text( - 'Enable swipe selection', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Enable swipe selection', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: 3, - child: Container( - padding: EdgeInsets.zero, - child: Theme( - data: Theme.of( - context, - ).copyWith(canvasColor: model.drawerBackgroundColor), - child: Container( - alignment: Alignment.centerLeft, - child: Transform.scale( - scale: 0.8, - child: CupertinoSwitch( - value: _enableSwipingSelection, - onChanged: (dynamic value) { - setState(() { - _onBoolValueChange( - 'EnableSwipingSelection', - value, - ); - stateSetter(() {}); - }); - }, - activeTrackColor: model.primaryColor, - ), - ), - ), + Theme( + data: Theme.of( + context, + ).copyWith(canvasColor: model.drawerBackgroundColor), + child: Transform.scale( + scale: 0.8, + child: CupertinoSwitch( + value: _enableSwipingSelection, + onChanged: (dynamic value) { + setState(() { + _onBoolValueChange('EnableSwipingSelection', value); + stateSetter(() {}); + }); + }, + activeTrackColor: model.primaryColor, ), ), ), @@ -698,38 +605,27 @@ class _HijriDatePickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: 7, - child: Text( - 'Show week number', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Show week number', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: 3, - child: Container( - padding: EdgeInsets.zero, - child: Theme( - data: Theme.of( - context, - ).copyWith(canvasColor: model.drawerBackgroundColor), - child: Container( - alignment: Alignment.centerLeft, - child: Transform.scale( - scale: 0.8, - child: CupertinoSwitch( - value: _showWeekNumber, - onChanged: (dynamic value) { - setState(() { - _onBoolValueChange('showWeekNumber', value); - stateSetter(() {}); - }); - }, - activeTrackColor: model.primaryColor, - ), - ), - ), + Theme( + data: Theme.of( + context, + ).copyWith(canvasColor: model.drawerBackgroundColor), + child: Transform.scale( + scale: 0.8, + child: CupertinoSwitch( + value: _showWeekNumber, + onChanged: (dynamic value) { + setState(() { + _onBoolValueChange('showWeekNumber', value); + stateSetter(() {}); + }); + }, + activeTrackColor: model.primaryColor, ), ), ), diff --git a/lib/samples/date_picker/vertical_calendar.dart b/lib/samples/date_picker/vertical_calendar.dart index daba0430..d2e794d4 100644 --- a/lib/samples/date_picker/vertical_calendar.dart +++ b/lib/samples/date_picker/vertical_calendar.dart @@ -42,42 +42,37 @@ class _VerticalCalendarPickerState extends SampleViewState { SizedBox( height: 50, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - flex: 6, - child: Text( - 'Navigation mode', - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + Text( + 'Navigation mode', + style: TextStyle(fontSize: 16.0, color: model.textColor), ), - Expanded( - flex: 4, - child: Container( - padding: EdgeInsets.zero, - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _navigationModeString, - items: _navigationModeList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'scroll', - child: Text( - value, - textAlign: TextAlign.center, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (dynamic value) { - _onNavigationModeChange(value); - stateSetter(() {}); - }, + Container( + padding: EdgeInsets.zero, + alignment: Alignment.bottomLeft, + child: DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, ), + value: _navigationModeString, + items: _navigationModeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'scroll', + child: Text( + value, + textAlign: TextAlign.center, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (dynamic value) { + _onNavigationModeChange(value); + stateSetter(() {}); + }, ), ), ], diff --git a/lib/samples/gauge/pointer_interaction/radial_range_slider.dart b/lib/samples/gauge/pointer_interaction/radial_range_slider.dart index 42579528..2e323548 100644 --- a/lib/samples/gauge/pointer_interaction/radial_range_slider.dart +++ b/lib/samples/gauge/pointer_interaction/radial_range_slider.dart @@ -136,6 +136,7 @@ class _RadialRangeSliderExampleState extends SampleViewState { children: [ SizedBox( child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Enable dragging', @@ -161,28 +162,24 @@ class _RadialRangeSliderExampleState extends SampleViewState { Visibility( visible: _enableDragging, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Overlay radius', style: TextStyle(color: model.textColor), ), - Container( - padding: !model.isWebFullView - ? const EdgeInsets.fromLTRB(25, 0, 0, 0) - : const EdgeInsets.fromLTRB(50, 0, 0, 0), - child: CustomDirectionalButtons( - maxValue: 35, - minValue: 15, - initialValue: _overlayRadius, - onChanged: (double val) { - setState(() { - _overlayRadius = val; - }); - }, - step: 5, - iconColor: model.textColor, - style: TextStyle(fontSize: 16.0, color: model.textColor), - ), + CustomDirectionalButtons( + maxValue: 35, + minValue: 15, + initialValue: _overlayRadius, + onChanged: (double val) { + setState(() { + _overlayRadius = val; + }); + }, + step: 5, + iconColor: model.textColor, + style: TextStyle(fontSize: 16.0, color: model.textColor), ), ], ), diff --git a/lib/samples/gauge/pointers/marker_pointer.dart b/lib/samples/gauge/pointers/marker_pointer.dart index a9208315..441368d6 100644 --- a/lib/samples/gauge/pointers/marker_pointer.dart +++ b/lib/samples/gauge/pointers/marker_pointer.dart @@ -59,38 +59,37 @@ class _MarkerPointerExampleState extends SampleViewState { shrinkWrap: true, children: [ Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Marker type ', style: TextStyle(color: model.textColor, fontSize: 16), ), - Container( - padding: const EdgeInsets.fromLTRB(20, 0, 0, 0), - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _selectedMarkerType, - items: _markerTypes.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'invertedTriangle', - child: Text( - value, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (String? value) { - _onMarkerTypeChange(value.toString()); - stateSetter(() {}); - }, + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, ), + value: _selectedMarkerType, + items: _markerTypes.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'invertedTriangle', + child: Text( + value, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (String? value) { + _onMarkerTypeChange(value.toString()); + stateSetter(() {}); + }, ), ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Elevation', diff --git a/lib/samples/pdf/conformance.dart b/lib/samples/pdf/conformance.dart index e1b440f4..0ad12dd1 100644 --- a/lib/samples/pdf/conformance.dart +++ b/lib/samples/pdf/conformance.dart @@ -54,10 +54,13 @@ class _ConformancePdfState extends SampleViewState { ), ), const SizedBox(height: 10, width: 25), - if (MediaQuery.of(context).size.width > 800) - Row(children: getChildWidgets(context)) - else - Column(children: getChildWidgets(context)), + RadioGroup( + groupValue: _groupValue, + onChanged: _changed, + child: (MediaQuery.of(context).size.width > 800) + ? Row(children: getChildWidgets(context)) + : Column(children: getChildWidgets(context)), + ), const SizedBox(height: 10, width: 30), Align( child: TextButton( @@ -92,7 +95,7 @@ class _ConformancePdfState extends SampleViewState { return [ Row( children: [ - Radio(groupValue: _groupValue, onChanged: _changed, value: 0), + const Radio(value: 0), Text( 'PDF/A-1B', style: TextStyle(fontSize: 16, color: model.textColor), @@ -101,7 +104,7 @@ class _ConformancePdfState extends SampleViewState { ), Row( children: [ - Radio(groupValue: _groupValue, onChanged: _changed, value: 1), + const Radio(value: 1), Text( 'PDF/A-2B', style: TextStyle(fontSize: 16, color: model.textColor), @@ -110,7 +113,7 @@ class _ConformancePdfState extends SampleViewState { ), Row( children: [ - Radio(groupValue: _groupValue, onChanged: _changed, value: 2), + const Radio(value: 2), Text( 'PDF/A-3B', style: TextStyle(fontSize: 16, color: model.textColor), diff --git a/lib/samples/pdf/digital_signature.dart b/lib/samples/pdf/digital_signature.dart index b91a183d..0380deff 100644 --- a/lib/samples/pdf/digital_signature.dart +++ b/lib/samples/pdf/digital_signature.dart @@ -36,6 +36,11 @@ class _SignPdfState extends SampleViewState { @override Widget build(BuildContext context) { + final double width = MediaQuery.of(context).size.width; + final List digestChildWidgets = getDigestChildWidgets(context); + final List cryptographicChildWidgets = getCryptographicChildWidgets( + context, + ); return Scaffold( backgroundColor: model.sampleOutputCardColor, body: SingleChildScrollView( @@ -58,10 +63,13 @@ class _SignPdfState extends SampleViewState { ), ), const SizedBox(height: 10, width: 30), - if (MediaQuery.of(context).size.width > 800) - Row(children: getCryptographicChildWidgets(context)) - else - Column(children: getCryptographicChildWidgets(context)), + RadioGroup( + groupValue: _cryptoGroupValue, + onChanged: _cryptoChanged, + child: (width > 800) + ? Row(children: cryptographicChildWidgets) + : Column(children: cryptographicChildWidgets), + ), const SizedBox(height: 20, width: 30), Text( 'Digest Algorithm', @@ -72,10 +80,13 @@ class _SignPdfState extends SampleViewState { ), ), const SizedBox(height: 10, width: 30), - if (MediaQuery.of(context).size.width > 800) - Row(children: getDigestChildWidgets(context)) - else - Column(children: getDigestChildWidgets(context)), + RadioGroup( + groupValue: _groupValue, + onChanged: _digestChanged, + child: (width > 800) + ? Row(children: digestChildWidgets) + : Column(children: digestChildWidgets), + ), const SizedBox(height: 10, width: 30), Align( child: TextButton( @@ -110,21 +121,13 @@ class _SignPdfState extends SampleViewState { return [ Row( children: [ - Radio( - value: 0, - groupValue: _groupValue, - onChanged: _digestChanged, - ), + const Radio(value: 0), Text('SHA1', style: TextStyle(fontSize: 16, color: model.textColor)), ], ), Row( children: [ - Radio( - value: 1, - groupValue: _groupValue, - onChanged: _digestChanged, - ), + const Radio(value: 1), Text( 'SHA256', style: TextStyle(fontSize: 16, color: model.textColor), @@ -133,11 +136,7 @@ class _SignPdfState extends SampleViewState { ), Row( children: [ - Radio( - value: 2, - groupValue: _groupValue, - onChanged: _digestChanged, - ), + const Radio(value: 2), Text( 'SHA384', style: TextStyle(fontSize: 16, color: model.textColor), @@ -146,11 +145,7 @@ class _SignPdfState extends SampleViewState { ), Row( children: [ - Radio( - value: 3, - groupValue: _groupValue, - onChanged: _digestChanged, - ), + const Radio(value: 3), Text( 'SHA512', style: TextStyle(fontSize: 16, color: model.textColor), @@ -164,21 +159,13 @@ class _SignPdfState extends SampleViewState { return [ Row( children: [ - Radio( - value: 0, - groupValue: _cryptoGroupValue, - onChanged: _cryptoChanged, - ), + const Radio(value: 0), Text('CMS', style: TextStyle(fontSize: 16, color: model.textColor)), ], ), Row( children: [ - Radio( - value: 1, - groupValue: _cryptoGroupValue, - onChanged: _cryptoChanged, - ), + const Radio(value: 1), Text('CAdES', style: TextStyle(fontSize: 16, color: model.textColor)), ], ), diff --git a/lib/samples/pdf/encryption.dart b/lib/samples/pdf/encryption.dart index a76e8e99..9ea62778 100644 --- a/lib/samples/pdf/encryption.dart +++ b/lib/samples/pdf/encryption.dart @@ -51,10 +51,13 @@ class _EncryptPdfState extends SampleViewState { ), ), const SizedBox(height: 10, width: 30), - if (MediaQuery.of(context).size.width > 800) - Row(children: getChildWidgets(context)) - else - Column(children: getChildWidgets(context)), + RadioGroup( + groupValue: _groupValue, + onChanged: _changed, + child: (MediaQuery.of(context).size.width > 800) + ? Row(children: getChildWidgets(context)) + : Column(children: getChildWidgets(context)), + ), const SizedBox(height: 10, width: 30), Row( children: [ @@ -123,7 +126,7 @@ class _EncryptPdfState extends SampleViewState { return [ Row( children: [ - Radio(value: 0, groupValue: _groupValue, onChanged: _changed), + const Radio(value: 0), Text( '40-bit RC4', style: TextStyle(fontSize: 16, color: model.textColor), @@ -132,7 +135,7 @@ class _EncryptPdfState extends SampleViewState { ), Row( children: [ - Radio(value: 1, groupValue: _groupValue, onChanged: _changed), + const Radio(value: 1), Text( '128-bit RC4', style: TextStyle(fontSize: 16, color: model.textColor), @@ -141,7 +144,7 @@ class _EncryptPdfState extends SampleViewState { ), Row( children: [ - Radio(value: 2, groupValue: _groupValue, onChanged: _changed), + const Radio(value: 2), Text( '128-bit AES', style: TextStyle(fontSize: 16, color: model.textColor), @@ -150,7 +153,7 @@ class _EncryptPdfState extends SampleViewState { ), Row( children: [ - Radio(value: 3, groupValue: _groupValue, onChanged: _changed), + const Radio(value: 3), Text( '256-bit AES', style: TextStyle(fontSize: 16, color: model.textColor), @@ -159,7 +162,7 @@ class _EncryptPdfState extends SampleViewState { ), Row( children: [ - Radio(value: 4, groupValue: _groupValue, onChanged: _changed), + const Radio(value: 4), Text( '256-bit AES Revision 6', style: TextStyle(fontSize: 16, color: model.textColor), diff --git a/lib/samples/pdf/form.dart b/lib/samples/pdf/form.dart index 4711d69f..bb7c0d7a 100644 --- a/lib/samples/pdf/form.dart +++ b/lib/samples/pdf/form.dart @@ -127,7 +127,11 @@ class _FormFillingPdfState extends SampleViewState { ), child: SizedBox( height: 25, - child: Row(children: _getGenderWidgets(context)), + child: RadioGroup( + groupValue: _groupValue, + onChanged: _changed, + child: Row(children: _getGenderWidgets(context)), + ), ), ), const SizedBox(height: 20, width: 30), @@ -151,11 +155,9 @@ class _FormFillingPdfState extends SampleViewState { ), const SizedBox(height: 20, width: 30), DropdownButtonFormField( - value: _dropdownValue, + initialValue: _dropdownValue, onChanged: (String? newValue) { - setState(() { - _dropdownValue = newValue!; - }); + _dropdownValue = newValue!; }, items: [ @@ -312,10 +314,8 @@ class _FormFillingPdfState extends SampleViewState { return [ Row( children: [ - Radio( + const Radio( value: 0, - groupValue: _groupValue, - onChanged: _changed, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, ), Text('Male', style: TextStyle(fontSize: 16, color: model.textColor)), @@ -323,10 +323,8 @@ class _FormFillingPdfState extends SampleViewState { ), Row( children: [ - Radio( + const Radio( value: 2, - groupValue: _groupValue, - onChanged: _changed, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, ), Text( @@ -337,10 +335,8 @@ class _FormFillingPdfState extends SampleViewState { ), Row( children: [ - Radio( + const Radio( value: 1, - groupValue: _groupValue, - onChanged: _changed, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, ), Text( diff --git a/lib/samples/pdf/helper/save_file_mobile.dart b/lib/samples/pdf/helper/save_file_mobile.dart index 729c8b90..c0ea70d8 100644 --- a/lib/samples/pdf/helper/save_file_mobile.dart +++ b/lib/samples/pdf/helper/save_file_mobile.dart @@ -1,7 +1,7 @@ -///Dart import +/// Dart import import 'dart:io'; -///Package imports +/// Package imports import 'package:flutter/services.dart'; import 'package:path_provider/path_provider.dart'; // ignore: depend_on_referenced_packages @@ -12,7 +12,7 @@ import 'package:path_provider_platform_interface/path_provider_platform_interfac class FileSaveHelper { static const MethodChannel _platformCall = MethodChannel('launchFile'); - ///To save the pdf file in the device + /// To save the pdf file in the device static Future saveAndLaunchFile( List bytes, String fileName, @@ -22,7 +22,7 @@ class FileSaveHelper { final Directory directory = await getApplicationSupportDirectory(); path = directory.path; } else if (Platform.isAndroid) { - final Directory? directory = await getExternalStorageDirectory(); + final Directory? directory = await getExternalFilesDirectory(); if (directory != null) { path = directory.path; } else { @@ -61,4 +61,13 @@ class FileSaveHelper { ], runInShell: true); } } + + /// Helper for app-private external storage directory on Android + static Future getExternalFilesDirectory() async { + try { + return await getExternalStorageDirectory(); + } catch (e) { + return null; + } + } } diff --git a/lib/samples/pdf/import_and_export_annotation_data.dart b/lib/samples/pdf/import_and_export_annotation_data.dart index cd7c8b7b..c904e6a8 100644 --- a/lib/samples/pdf/import_and_export_annotation_data.dart +++ b/lib/samples/pdf/import_and_export_annotation_data.dart @@ -61,6 +61,7 @@ class _ImportAndExportAnnotationDataState extends SampleViewState { @override Widget build(BuildContext context) { + final double width = MediaQuery.of(context).size.width; return Scaffold( backgroundColor: model.sampleOutputCardColor, body: SingleChildScrollView( @@ -83,10 +84,13 @@ class _ImportAndExportAnnotationDataState extends SampleViewState { ), ), const SizedBox(height: 10, width: 30), - if (MediaQuery.of(context).size.width > 800) - Row(children: getDataTypeChildWidgets(context)) - else - Column(children: getDataTypeChildWidgets(context)), + RadioGroup( + groupValue: _groupDataTypeValue, + onChanged: _dataTypeChanged, + child: (width > 800) + ? Row(children: getDataTypeChildWidgets(context)) + : Column(children: getDataTypeChildWidgets(context)), + ), const SizedBox(height: 20, width: 30), Text( 'Select import or export:', @@ -97,10 +101,13 @@ class _ImportAndExportAnnotationDataState extends SampleViewState { ), ), const SizedBox(height: 10, width: 30), - if (MediaQuery.of(context).size.width > 800) - Row(children: getProcessChildWidgets(context)) - else - Column(children: getProcessChildWidgets(context)), + RadioGroup( + groupValue: _groupProcessValue, + onChanged: _processChanged, + child: (width > 800) + ? Row(children: getProcessChildWidgets(context)) + : Column(children: getProcessChildWidgets(context)), + ), const SizedBox(height: 20, width: 30), Row( mainAxisAlignment: MainAxisAlignment.center, @@ -160,31 +167,19 @@ class _ImportAndExportAnnotationDataState extends SampleViewState { return [ Row( children: [ - Radio( - value: 0, - groupValue: _groupDataTypeValue, - onChanged: _dataTypeChanged, - ), + const Radio(value: 0), Text('XFDF', style: TextStyle(fontSize: 16, color: model.textColor)), ], ), Row( children: [ - Radio( - value: 1, - groupValue: _groupDataTypeValue, - onChanged: _dataTypeChanged, - ), + const Radio(value: 1), Text('JSON', style: TextStyle(fontSize: 16, color: model.textColor)), ], ), Row( children: [ - Radio( - value: 2, - groupValue: _groupDataTypeValue, - onChanged: _dataTypeChanged, - ), + const Radio(value: 2), Text('FDF', style: TextStyle(fontSize: 16, color: model.textColor)), ], ), @@ -195,11 +190,7 @@ class _ImportAndExportAnnotationDataState extends SampleViewState { return [ Row( children: [ - Radio( - value: 0, - groupValue: _groupProcessValue, - onChanged: _processChanged, - ), + const Radio(value: 0), Text( 'Import', style: TextStyle(fontSize: 16, color: model.textColor), @@ -208,11 +199,7 @@ class _ImportAndExportAnnotationDataState extends SampleViewState { ), Row( children: [ - Radio( - value: 1, - groupValue: _groupProcessValue, - onChanged: _processChanged, - ), + const Radio(value: 1), Text( 'Export', style: TextStyle(fontSize: 16, color: model.textColor), diff --git a/lib/samples/pdf/import_and_export_form_data.dart b/lib/samples/pdf/import_and_export_form_data.dart index 976efcf7..b24a8fe9 100644 --- a/lib/samples/pdf/import_and_export_form_data.dart +++ b/lib/samples/pdf/import_and_export_form_data.dart @@ -63,6 +63,7 @@ class _ImportAndExportFormDataState extends SampleViewState { @override Widget build(BuildContext context) { + final double width = MediaQuery.of(context).size.width; return Scaffold( backgroundColor: model.sampleOutputCardColor, body: SingleChildScrollView( @@ -85,10 +86,14 @@ class _ImportAndExportFormDataState extends SampleViewState { ), ), const SizedBox(height: 10, width: 30), - if (MediaQuery.of(context).size.width > 800) - Row(children: getDataTypeChildWidgets(context)) - else - Column(children: getDataTypeChildWidgets(context)), + RadioGroup( + groupValue: _groupDataTypeValue, + onChanged: _dataTypeChanged, + child: (width > 800) + ? Row(children: getDataTypeChildWidgets(context)) + : Column(children: getDataTypeChildWidgets(context)), + ), + const SizedBox(height: 20, width: 30), Text( 'Select import or export:', @@ -99,10 +104,13 @@ class _ImportAndExportFormDataState extends SampleViewState { ), ), const SizedBox(height: 10, width: 30), - if (MediaQuery.of(context).size.width > 800) - Row(children: getProcessChildWidgets(context)) - else - Column(children: getProcessChildWidgets(context)), + RadioGroup( + groupValue: _groupProcessValue, + onChanged: _processChanged, + child: (width > 800) + ? Row(children: getProcessChildWidgets(context)) + : Column(children: getProcessChildWidgets(context)), + ), const SizedBox(height: 20, width: 30), Row( mainAxisAlignment: MainAxisAlignment.center, @@ -162,31 +170,19 @@ class _ImportAndExportFormDataState extends SampleViewState { return [ Row( children: [ - Radio( - value: 0, - groupValue: _groupDataTypeValue, - onChanged: _dataTypeChanged, - ), + const Radio(value: 0), Text('XFDF', style: TextStyle(fontSize: 16, color: model.textColor)), ], ), Row( children: [ - Radio( - value: 1, - groupValue: _groupDataTypeValue, - onChanged: _dataTypeChanged, - ), + const Radio(value: 1), Text('JSON', style: TextStyle(fontSize: 16, color: model.textColor)), ], ), Row( children: [ - Radio( - value: 2, - groupValue: _groupDataTypeValue, - onChanged: _dataTypeChanged, - ), + const Radio(value: 2), Text('XML', style: TextStyle(fontSize: 16, color: model.textColor)), ], ), @@ -197,11 +193,7 @@ class _ImportAndExportFormDataState extends SampleViewState { return [ Row( children: [ - Radio( - value: 0, - groupValue: _groupProcessValue, - onChanged: _processChanged, - ), + const Radio(value: 0), Text( 'Import', style: TextStyle(fontSize: 16, color: model.textColor), @@ -210,11 +202,7 @@ class _ImportAndExportFormDataState extends SampleViewState { ), Row( children: [ - Radio( - value: 1, - groupValue: _groupProcessValue, - onChanged: _processChanged, - ), + const Radio(value: 1), Text( 'Export', style: TextStyle(fontSize: 16, color: model.textColor), diff --git a/lib/samples/pdf_viewer/pdf_viewer_custom_toolbar.dart b/lib/samples/pdf_viewer/pdf_viewer_custom_toolbar.dart index 04ed739c..3fd183ab 100644 --- a/lib/samples/pdf_viewer/pdf_viewer_custom_toolbar.dart +++ b/lib/samples/pdf_viewer/pdf_viewer_custom_toolbar.dart @@ -1962,9 +1962,6 @@ class _CustomToolbarPdfViewerState extends SampleViewState { }); } if (toolbarItem.toString() == 'Bookmarks') { - setState(() { - _canShowToolbar = false; - }); _pdfViewerKey.currentState?.openBookmarkView(); } else if (toolbarItem.toString() == 'Search') { setState(() { diff --git a/lib/samples/pdf_viewer/shared/toolbar_widgets.dart b/lib/samples/pdf_viewer/shared/toolbar_widgets.dart index 602f1a3c..bdf07a7c 100644 --- a/lib/samples/pdf_viewer/shared/toolbar_widgets.dart +++ b/lib/samples/pdf_viewer/shared/toolbar_widgets.dart @@ -530,7 +530,7 @@ class SearchToolbarState extends State { /// Toolbar item widget class ToolbarItem extends StatelessWidget { ///Creates a toolbar item - const ToolbarItem({Key? key, this.height, this.width, @required this.child}) + const ToolbarItem({Key? key, this.height, this.width, required this.child}) : super(key: key); /// Height of the toolbar item diff --git a/lib/samples/radial_range_slider/basic_features/state.dart b/lib/samples/radial_range_slider/basic_features/state.dart index ea5ece87..79746e62 100644 --- a/lib/samples/radial_range_slider/basic_features/state.dart +++ b/lib/samples/radial_range_slider/basic_features/state.dart @@ -120,6 +120,7 @@ class _RadialRangeSliderStateTypesState extends SampleViewState { return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Enable drag', style: TextStyle(color: model.textColor)), Padding( diff --git a/lib/samples/radial_slider/basic_features/state.dart b/lib/samples/radial_slider/basic_features/state.dart index cdd4f04f..8d7ad0d3 100644 --- a/lib/samples/radial_slider/basic_features/state.dart +++ b/lib/samples/radial_slider/basic_features/state.dart @@ -113,6 +113,7 @@ class _RadialSliderStateTypesState extends SampleViewState { return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Enable drag', style: TextStyle(color: model.textColor)), Padding( diff --git a/lib/samples/sliders/range_selector/range_selector_label_customization.dart b/lib/samples/sliders/range_selector/range_selector_label_customization.dart index 67675ff8..0d3e9435 100644 --- a/lib/samples/sliders/range_selector/range_selector_label_customization.dart +++ b/lib/samples/sliders/range_selector/range_selector_label_customization.dart @@ -69,7 +69,7 @@ class _RangeSelectorLabelCustomizationState extends SampleViewState chartData.add( ChartSampleData( x: DateTime(2000).add(Duration(days: i)), - y: Random().nextInt(190) + 50, + y: Random.secure().nextInt(190) + 50, ), ); } diff --git a/lib/samples/sliders/range_selector/range_selector_with_zooming.dart b/lib/samples/sliders/range_selector/range_selector_with_zooming.dart index 088ff937..88ef1c35 100644 --- a/lib/samples/sliders/range_selector/range_selector_with_zooming.dart +++ b/lib/samples/sliders/range_selector/range_selector_with_zooming.dart @@ -54,7 +54,7 @@ class _RangeSelectorZoomingPageState extends SampleViewState chartData.add( ChartSampleData( x: DateTime(2000).add(Duration(days: i)), - y: Random().nextInt(190) + 50, + y: Random.secure().nextInt(190) + 50, ), ); } diff --git a/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_tooltip_position.dart b/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_tooltip_position.dart index 05f70adc..7b483266 100644 --- a/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_tooltip_position.dart +++ b/lib/samples/sliders/vertical_range_slider/default_appearance/vertical_range_slider_tooltip_position.dart @@ -100,7 +100,7 @@ class _VerticalTooltipRangeSliderPageState extends SampleViewState { } Widget _buildMobileLayout() { - final double padding = MediaQuery.of(context).size.height / 10.0; + final double padding = MediaQuery.of(context).size.height / 12.0; return Padding( padding: EdgeInsets.all(padding), child: Row( @@ -144,6 +144,7 @@ class _VerticalTooltipRangeSliderPageState extends SampleViewState { return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return Column( + mainAxisSize: MainAxisSize.min, children: [ CheckboxListTile( value: _isInversed, diff --git a/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_tooltip_position.dart b/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_tooltip_position.dart index aa5aa43f..e6cafd99 100644 --- a/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_tooltip_position.dart +++ b/lib/samples/sliders/vertical_slider/basic_features/vertical_slider_tooltip_position.dart @@ -99,7 +99,7 @@ class _VerticalSliderTooltipPageState extends SampleViewState { } Widget _buildMobileLayout() { - final double padding = MediaQuery.of(context).size.height / 10.0; + final double padding = MediaQuery.of(context).size.height / 12.0; return Padding( padding: EdgeInsets.all(padding), child: Row( @@ -143,6 +143,7 @@ class _VerticalSliderTooltipPageState extends SampleViewState { return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return Column( + mainAxisSize: MainAxisSize.min, children: [ CheckboxListTile( value: _isInversed, @@ -158,7 +159,7 @@ class _VerticalSliderTooltipPageState extends SampleViewState { ), CheckboxListTile( value: _shouldAlwaysShowTooltip, - title: const Text('Show tooltip always', softWrap: false), + title: const Text('Show tooltip always'), activeColor: model.primaryColor, contentPadding: EdgeInsets.zero, onChanged: (bool? value) { diff --git a/lib/samples/sparkline/customization.dart b/lib/samples/sparkline/customization.dart index 46c3f44a..4bd5a571 100644 --- a/lib/samples/sparkline/customization.dart +++ b/lib/samples/sparkline/customization.dart @@ -129,159 +129,151 @@ class _SparklineCustomizationState extends SampleViewState { return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { return ListView( + padding: const EdgeInsets.only(right: 10), shrinkWrap: true, children: [ Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Marker', style: TextStyle(color: model.textColor, fontSize: 16), ), - const Padding(padding: EdgeInsets.fromLTRB(75, 0, 0, 0)), - Container( - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _selectedMarkerDisplayMode, - items: _markerDisplayModeList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'none', - child: Text( - value, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (String? value) { - _onMarkerDisplayModeChange(value.toString()); - stateSetter(() {}); - }, + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, ), + value: _selectedMarkerDisplayMode, + items: _markerDisplayModeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'none', + child: Text( + value, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (String? value) { + _onMarkerDisplayModeChange(value.toString()); + stateSetter(() {}); + }, ), ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Data label', style: TextStyle(color: model.textColor, fontSize: 16), ), - const Padding(padding: EdgeInsets.fromLTRB(55, 0, 0, 0)), - Container( - height: 50, - alignment: Alignment.bottomLeft, - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - focusColor: Colors.transparent, - underline: Container( - color: const Color(0xFFBDBDBD), - height: 1, - ), - value: _selectedDatalabelDisplayMode, - items: _datalabelDisplayModeList.map((String value) { - return DropdownMenuItem( - value: (value != null) ? value : 'none', - child: Text( - value, - style: TextStyle(color: model.textColor), - ), - ); - }).toList(), - onChanged: (String? value) { - _onDatalabelDisplayModeChange(value.toString()); - stateSetter(() {}); - }, + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + focusColor: Colors.transparent, + underline: Container( + color: const Color(0xFFBDBDBD), + height: 1, ), + value: _selectedDatalabelDisplayMode, + items: _datalabelDisplayModeList.map((String value) { + return DropdownMenuItem( + value: (value != null) ? value : 'none', + child: Text( + value, + style: TextStyle(color: model.textColor), + ), + ); + }).toList(), + onChanged: (String? value) { + _onDatalabelDisplayModeChange(value.toString()); + stateSetter(() {}); + }, ), ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Trackball', style: TextStyle(color: model.textColor, fontSize: 16), ), - const Padding(padding: EdgeInsets.fromLTRB(16, 0, 0, 0)), - SizedBox( - width: 90, - child: CheckboxListTile( - activeColor: model.primaryColor, - value: _enableTrackLine, - onChanged: (bool? value) { - setState(() { - _enableTrackLine = value!; - stateSetter(() {}); - }); - }, - ), + Checkbox( + activeColor: model.primaryColor, + value: _enableTrackLine, + onChanged: (bool? value) { + setState(() { + _enableTrackLine = value!; + stateSetter(() {}); + }); + }, ), ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Axis value', style: TextStyle(color: model.textColor, fontSize: 16), ), - const Padding(padding: EdgeInsets.fromLTRB(30, 0, 0, 0)), - SizedBox( - width: 150, - child: SliderTheme( - data: SliderThemeData( - tickMarkShape: SliderTickMarkShape.noTickMark, + Row( + spacing: 2, + children: [ + SizedBox( + width: 130, + child: SliderTheme( + data: SliderThemeData( + tickMarkShape: SliderTickMarkShape.noTickMark, + ), + child: Slider( + value: _axisCrossingValue, + min: -10, + max: 13, + divisions: 24, + onChanged: (double value) { + setState(() { + _axisCrossingValue = value; + stateSetter(() {}); + }); + }, + ), + ), ), - child: Slider( - value: _axisCrossingValue, - min: -10, - max: 13, - divisions: 24, - onChanged: (double value) { - setState(() { - _axisCrossingValue = value; - stateSetter(() {}); - }); - }, + Text( + '${_axisCrossingValue.floor()}', + style: TextStyle(color: model.textColor, fontSize: 16), ), - ), - ), - const Padding(padding: EdgeInsets.fromLTRB(2, 0, 0, 0)), - Text( - '${_axisCrossingValue.floor()}', - style: TextStyle(color: model.textColor, fontSize: 16), + ], ), ], ), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Plot band', style: TextStyle(color: model.textColor, fontSize: 16), ), - const Padding(padding: EdgeInsets.fromLTRB(12, 0, 0, 0)), - SizedBox( - width: 90, - child: CheckboxListTile( - activeColor: model.primaryColor, - value: _enablePlotband, - onChanged: (bool? value) { - setState(() { - _enablePlotband = value!; - stateSetter(() {}); - }); - }, - ), + Checkbox( + activeColor: model.primaryColor, + value: _enablePlotband, + onChanged: (bool? value) { + setState(() { + _enablePlotband = value!; + stateSetter(() {}); + }); + }, ), ], ), Visibility( visible: _enablePlotband, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( mainAxisAlignment: MainAxisAlignment.center, @@ -295,7 +287,6 @@ class _SparklineCustomizationState extends SampleViewState { ), ], ), - const Padding(padding: EdgeInsets.fromLTRB(20, 0, 0, 0)), Column( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -324,6 +315,7 @@ class _SparklineCustomizationState extends SampleViewState { Visibility( visible: _enablePlotband, child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( mainAxisAlignment: MainAxisAlignment.center, @@ -337,7 +329,6 @@ class _SparklineCustomizationState extends SampleViewState { ), ], ), - const Padding(padding: EdgeInsets.fromLTRB(25, 0, 0, 0)), Column( mainAxisAlignment: MainAxisAlignment.center, children: [ diff --git a/lib/samples/sparkline/live_update.dart b/lib/samples/sparkline/live_update.dart index 9f384dd5..befd6980 100644 --- a/lib/samples/sparkline/live_update.dart +++ b/lib/samples/sparkline/live_update.dart @@ -364,7 +364,7 @@ class _SparklineLiveUpdateState extends SampleViewState { ///Get random value double _getRandomInt(int min, int max) { - final Random random = Random(); + final Random random = Random.secure(); return min + random.nextInt(max - min).toDouble(); } diff --git a/lib/samples/treemap/hierarchical.dart b/lib/samples/treemap/hierarchical.dart index 0fdabdcc..1921a877 100644 --- a/lib/samples/treemap/hierarchical.dart +++ b/lib/samples/treemap/hierarchical.dart @@ -316,35 +316,30 @@ class _HierarchicalTreemapSampleState extends SampleViewState { 'Layout direction', style: TextStyle(color: model.textColor, fontSize: 16), ), - Padding( - padding: const EdgeInsets.only(right: 15.0), - child: DropdownButton( - dropdownColor: model.drawerBackgroundColor, - value: _layoutDirection, - items: _dropDownMenuItems, - onChanged: (TreemapLayoutDirection? value) { - setState(() { - _layoutDirection = value!; - switch (_layoutDirection) { - case TreemapLayoutDirection.topLeft: - _layoutDirection = TreemapLayoutDirection.topLeft; - break; - case TreemapLayoutDirection.topRight: - _layoutDirection = TreemapLayoutDirection.topRight; - break; - case TreemapLayoutDirection.bottomLeft: - _layoutDirection = - TreemapLayoutDirection.bottomLeft; - break; - case TreemapLayoutDirection.bottomRight: - _layoutDirection = - TreemapLayoutDirection.bottomRight; - break; - } - stateSetter(() {}); - }); - }, - ), + DropdownButton( + dropdownColor: model.drawerBackgroundColor, + value: _layoutDirection, + items: _dropDownMenuItems, + onChanged: (TreemapLayoutDirection? value) { + setState(() { + _layoutDirection = value!; + switch (_layoutDirection) { + case TreemapLayoutDirection.topLeft: + _layoutDirection = TreemapLayoutDirection.topLeft; + break; + case TreemapLayoutDirection.topRight: + _layoutDirection = TreemapLayoutDirection.topRight; + break; + case TreemapLayoutDirection.bottomLeft: + _layoutDirection = TreemapLayoutDirection.bottomLeft; + break; + case TreemapLayoutDirection.bottomRight: + _layoutDirection = TreemapLayoutDirection.bottomRight; + break; + } + stateSetter(() {}); + }); + }, ), ], ), diff --git a/lib/showcase_samples/expense_tracker/helper/common_helper.dart b/lib/showcase_samples/expense_tracker/helper/common_helper.dart index f0507745..eaf1da51 100644 --- a/lib/showcase_samples/expense_tracker/helper/common_helper.dart +++ b/lib/showcase_samples/expense_tracker/helper/common_helper.dart @@ -49,7 +49,7 @@ List randomColors(BuildContext context) { context, listen: false, ); - final Random random = Random(); + final Random random = Random.secure(); final List cardAvatarColors = _cardAvatarColors(themeNotifier); return List.generate(10, (int index) { diff --git a/lib/showcase_samples/expense_tracker/pages/base_home.dart b/lib/showcase_samples/expense_tracker/pages/base_home.dart index f40612f0..0d0e5608 100644 --- a/lib/showcase_samples/expense_tracker/pages/base_home.dart +++ b/lib/showcase_samples/expense_tracker/pages/base_home.dart @@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import '../../../meta_tag/meta_tag.dart'; import '../constants.dart'; // import '../data_processing/budget_handler.dart' // if (dart.library.html) '../data_processing/budget_web_handler.dart'; @@ -70,11 +71,29 @@ class _ExpenseAnalysisState extends State { final GlobalKey> _popupMenuKey = GlobalKey(); final GlobalKey> _profilePopupMenuKey = GlobalKey(); + final WebMetaTagUpdate metaTagUpdate = WebMetaTagUpdate(); + + void _onPageNavigatorChanged() { + final String pageTitle = _buildPageTitle( + context, + pageNavigatorNotifier.value, + ); + metaTagUpdate.update(pageTitle, 'Expense Tracker'); + } @override void initState() { currentUserDetails = widget.currentUserDetails; super.initState(); + + // Updates meta tag details when navigating from the import page + // to the dashboard page in Expense Tracker. + metaTagUpdate.update( + _buildPageTitle(context, pageNavigatorNotifier.value), + 'Expense Tracker', + ); + + pageNavigatorNotifier.addListener(_onPageNavigatorChanged); } @override @@ -89,6 +108,7 @@ class _ExpenseAnalysisState extends State { _isAccountPageActive.dispose(); _isGoalsPageActive.dispose(); _appBarTitle.dispose(); + pageNavigatorNotifier.removeListener(_onPageNavigatorChanged); super.dispose(); } @@ -799,6 +819,9 @@ class _ExpenseAnalysisState extends State { mouseCursor: SystemMouseCursors.click, onTap: () { Navigator.of(context, rootNavigator: true).pop(context); + // Sets default meta tag details when navigating back from the + // Expense Tracker to the home page. + metaTagUpdate.setDefault(); }, child: Padding( padding: const EdgeInsets.only(left: 10), diff --git a/lib/showcase_samples/expense_tracker/pages/settings/sections/appearance.dart b/lib/showcase_samples/expense_tracker/pages/settings/sections/appearance.dart index e8135781..a1d72a0a 100644 --- a/lib/showcase_samples/expense_tracker/pages/settings/sections/appearance.dart +++ b/lib/showcase_samples/expense_tracker/pages/settings/sections/appearance.dart @@ -186,30 +186,28 @@ class _AppearancePageState extends State { ) { return InkWell( onTap: () => _updateTheme(title), - child: Row( - children: [ - Center( - child: Radio( - value: title, - groupValue: themeNotifier.selectedTheme, - onChanged: (value) => _updateTheme(value!), - ), - ), - horizontalSpacer14, - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: textTheme.bodyLarge?.copyWith( - color: colorScheme.onSurface, + child: RadioGroup( + groupValue: themeNotifier.selectedTheme, + onChanged: (value) => _updateTheme(value!), + child: Row( + children: [ + Center(child: Radio(value: title)), + horizontalSpacer14, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: textTheme.bodyLarge?.copyWith( + color: colorScheme.onSurface, + ), ), - ), - ], + ], + ), ), - ), - ], + ], + ), ), ); } diff --git a/lib/showcase_samples/expense_tracker/pages/settings/settings.dart b/lib/showcase_samples/expense_tracker/pages/settings/settings.dart index 6f079384..b55f8396 100644 --- a/lib/showcase_samples/expense_tracker/pages/settings/settings.dart +++ b/lib/showcase_samples/expense_tracker/pages/settings/settings.dart @@ -289,8 +289,7 @@ class _SettingsPageState extends State { await excelFile.delete(); } } - } catch (e, stackTrace) { - debugPrint('Error deleting app data: $e\n$stackTrace'); + } catch (e) { throw Exception('Failed to delete app data: $e'); } } diff --git a/lib/showcase_samples/expense_tracker/pages/welcome_screens/import_page.dart b/lib/showcase_samples/expense_tracker/pages/welcome_screens/import_page.dart index 0cae8bbc..fec94a8d 100644 --- a/lib/showcase_samples/expense_tracker/pages/welcome_screens/import_page.dart +++ b/lib/showcase_samples/expense_tracker/pages/welcome_screens/import_page.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import '../../../../meta_tag/meta_tag.dart'; import '../../base.dart'; import '../../constants.dart'; // import '../../data_processing/utils.dart'; @@ -34,6 +35,7 @@ class ImportPageState extends State { VerifyUserNotifier? _homeScreenNotifier; ImportNotifier? _importNotifier; + final WebMetaTagUpdate metaTagUpdate = WebMetaTagUpdate(); Widget _buildMobileLayout(BuildContext context) { return Padding( @@ -353,6 +355,11 @@ class ImportPageState extends State { listen: false, ); _importNotifier = Provider.of(context, listen: false); + + // Updates meta tag details when navigating from the setup page to the + // import page in Expense Tracker. + metaTagUpdate.update('Import', 'Expense Tracker'); + super.didChangeDependencies(); } diff --git a/lib/showcase_samples/expense_tracker/pages/welcome_screens/setup_page.dart b/lib/showcase_samples/expense_tracker/pages/welcome_screens/setup_page.dart index 3255006b..985e11d3 100644 --- a/lib/showcase_samples/expense_tracker/pages/welcome_screens/setup_page.dart +++ b/lib/showcase_samples/expense_tracker/pages/welcome_screens/setup_page.dart @@ -4,6 +4,7 @@ import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; +import '../../../../meta_tag/meta_tag.dart'; import '../../constants.dart'; import '../../custom_widgets/custom_drop_down_menu.dart'; import '../../custom_widgets/single_selection_date_picker.dart'; @@ -54,6 +55,7 @@ class SetupProfilePageState extends State { late WelcomeScreenNotifier _pageNotifier; late ImportNotifier _importNotifier; DateTime? _selectedDate; + final WebMetaTagUpdate metaTagUpdate = WebMetaTagUpdate(); /// Initializes all controllers, notifiers, and focus nodes. void _initializeFields() { @@ -165,6 +167,10 @@ class SetupProfilePageState extends State { ), onPressed: () { Navigator.of(context, rootNavigator: true).pop(context); + + // Sets default meta tag details when navigating from the + // sign-up page to the home page. + metaTagUpdate.setDefault(); }, child: Row( mainAxisSize: MainAxisSize.min, @@ -576,6 +582,13 @@ class SetupProfilePageState extends State { _setupNotifier = Provider.of(context, listen: false); _pageNotifier = Provider.of(context, listen: false); _importNotifier = Provider.of(context, listen: false); + + if (_pageNotifier.currentPage == WelcomeScreens.setupPage) { + // Updates meta tag details when navigating from the home page to the + // expense tracker setup (sign-up) page. + metaTagUpdate.update('Setup', 'Expense Tracker'); + } + super.didChangeDependencies(); } diff --git a/lib/showcase_samples/stock_analysis/dialogs/settings.dart b/lib/showcase_samples/stock_analysis/dialogs/settings.dart index 22f04ccf..acf0c39a 100644 --- a/lib/showcase_samples/stock_analysis/dialogs/settings.dart +++ b/lib/showcase_samples/stock_analysis/dialogs/settings.dart @@ -218,49 +218,45 @@ class SettingsDialog extends StatelessWidget { selector: (BuildContext context, StockChartProvider provider) => provider.tempSettings.logarithmicYAxis, builder: (BuildContext context, bool isLogarithmic, Widget? child) => - Row( - children: [ - Expanded( - child: RadioListTile( - title: Text( - 'Numeric Axis', - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: Theme.of(context).colorScheme.onSurface, - fontWeight: fontWeight400(), + RadioGroup( + groupValue: isLogarithmic, + onChanged: (bool? value) { + if (value != null) { + context.read().updateTempSetting( + logarithmicYAxis: value, + ); + } + }, + child: Row( + children: [ + Expanded( + child: RadioListTile( + title: Text( + 'Numeric Axis', + style: Theme.of(context).textTheme.bodyMedium + ?.copyWith( + color: Theme.of(context).colorScheme.onSurface, + fontWeight: fontWeight400(), + ), ), + value: false, ), - value: false, - groupValue: isLogarithmic, - onChanged: (bool? value) { - if (value != null) { - context.read().updateTempSetting( - logarithmicYAxis: value, - ); - } - }, ), - ), - Expanded( - child: RadioListTile( - title: Text( - 'Log Axis', - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: Theme.of(context).colorScheme.onSurface, - fontWeight: fontWeight400(), + Expanded( + child: RadioListTile( + title: Text( + 'Log Axis', + style: Theme.of(context).textTheme.bodyMedium + ?.copyWith( + color: Theme.of(context).colorScheme.onSurface, + fontWeight: fontWeight400(), + ), ), + value: true, ), - value: true, - groupValue: isLogarithmic, - onChanged: (bool? value) { - if (value != null) { - context.read().updateTempSetting( - logarithmicYAxis: value, - ); - } - }, ), - ), - ], + ], + ), ), ), ], diff --git a/lib/showcase_samples/stock_analysis/screens/setup.dart b/lib/showcase_samples/stock_analysis/screens/setup.dart index c2db5fda..5501edf7 100644 --- a/lib/showcase_samples/stock_analysis/screens/setup.dart +++ b/lib/showcase_samples/stock_analysis/screens/setup.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; +import '../../../meta_tag/meta_tag.dart'; import '../enum.dart'; import '../helper/helper.dart'; import '../helper/responsive_layout.dart'; @@ -55,6 +56,7 @@ class SetupProfilePage extends StatefulWidget { class SetupProfilePageState extends State { late final TextEditingController _firstNameController; late final TextEditingController _lastNameController; + final WebMetaTagUpdate metaTagUpdate = WebMetaTagUpdate(); @override void initState() { @@ -396,6 +398,10 @@ class SetupProfilePageState extends State { context.read().isLoading = false; } } + + // Updates meta tag details when navigating from the setup page + // to the Stock Chart page in Stock Analysis. + metaTagUpdate.update('Stock Chart', 'Stock Analysis'); }, child: const Text('Skip', textAlign: TextAlign.left), ), @@ -421,6 +427,10 @@ class SetupProfilePageState extends State { context.read().isLoading = false; } } + + // Updates meta tag details when navigating from the + // setup page to the Stock Chart page in Stock Analysis. + metaTagUpdate.update('Stock Chart', 'Stock Analysis'); } : null, child: Text( diff --git a/lib/showcase_samples/stock_analysis/screens/splash.dart b/lib/showcase_samples/stock_analysis/screens/splash.dart index ccaf16a1..aeb20efd 100644 --- a/lib/showcase_samples/stock_analysis/screens/splash.dart +++ b/lib/showcase_samples/stock_analysis/screens/splash.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import '../../../meta_tag/meta_tag.dart'; + /// A widget that displays a splash screen with animation. class SplashScreen extends StatefulWidget { const SplashScreen({required this.nextScreen, super.key}); @@ -19,6 +21,7 @@ class _SplashScreenState extends State /// Animation for fading effect. late final Animation _fadeAnimation; + final WebMetaTagUpdate metaTagUpdate = WebMetaTagUpdate(); /// Initializes animations for the splash screen. void _initializeAnimations() { @@ -95,6 +98,10 @@ class _SplashScreenState extends State super.initState(); _initializeAnimations(); _startNavigationTimer(); + + // Updates meta tag details when navigating from the home page to the + // setup page in Stock Analysis. + metaTagUpdate.update('Setup page', 'Stock Analysis'); } @override diff --git a/lib/showcase_samples/stock_analysis/stock_home/stock_chart_view/profile_menu_popup.dart b/lib/showcase_samples/stock_analysis/stock_home/stock_chart_view/profile_menu_popup.dart index 208b2a39..92802581 100644 --- a/lib/showcase_samples/stock_analysis/stock_home/stock_chart_view/profile_menu_popup.dart +++ b/lib/showcase_samples/stock_analysis/stock_home/stock_chart_view/profile_menu_popup.dart @@ -1,8 +1,11 @@ import 'package:flutter/material.dart'; +import '../../../../meta_tag/meta_tag.dart'; import '../../helper/helper.dart'; import '../settings_page.dart'; +final WebMetaTagUpdate metaTagUpdate = WebMetaTagUpdate(); + class ProfileMenuPopup extends StatelessWidget { const ProfileMenuPopup( this.firstNameFirstLetter, @@ -85,6 +88,10 @@ class ProfileMenuPopup extends StatelessWidget { mouseCursor: SystemMouseCursors.click, onTap: () { Navigator.of(context, rootNavigator: true).pop(context); + + // Reset meta tags to default when navigating from Stock Analyst + // page to Home page. + metaTagUpdate.setDefault(); }, child: Padding( padding: const EdgeInsets.only(left: 10), diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/CHANGELOG.md b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/CHANGELOG.md new file mode 100644 index 00000000..c02c0c58 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/CHANGELOG.md @@ -0,0 +1,30 @@ +## 0.4.2 - 2024/10/29 +* windows: fix crash issue + + +## 0.4.1 - 2024/10/04 +* macos: Use first window when mainWindow is nil + + +## 0.4.0 - 2021/03/09 +* null safety + + +## 0.3.0 - 2020/10/08 +* add Windows support + + +## 0.2.0 - 2020/09/04 +* add Linux support +* add getFullScreen and setFullScreen functions + + +## 0.1.0 - 2020/05/25 + +* add setMaxWindowSize, setMinWindowSize +* add toggleFullScreen + + +## 0.0.1 - 2020/05/25 + +* initial release diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/lib/main.dart b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/lib/main.dart new file mode 100644 index 00000000..efb7322d --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/lib/main.dart @@ -0,0 +1,180 @@ +import 'package:flutter/material.dart'; +import 'dart:async'; + +import 'package:desktop_window/desktop_window.dart'; + +void main() { + runApp(MyApp()); +} + +class MyApp extends StatefulWidget { + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + String _windowSize = 'Unknown'; + + @override + void initState() { + super.initState(); + } + + Future _getWindowSize() async { + var size = await DesktopWindow.getWindowSize(); + setState(() { + _windowSize = '${size.width} x ${size.height}'; + }); + } + + @override + Widget build(BuildContext context) { + // MediaQuery.of(context).size; + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('desktop_window example app'), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('$_windowSize\n'), + ElevatedButton( + child: Text("getWindowSize"), + onPressed: _getWindowSize, + ), + ElevatedButton( + child: Text("setMinWindowSize(300,400)"), + onPressed: () async { + await DesktopWindow.setMinWindowSize(Size(300, 400)); + }, + ), + ElevatedButton( + child: Text("setMaxWindowSize(800,800)"), + onPressed: () async { + await DesktopWindow.setMaxWindowSize(Size(800, 800)); + }, + ), + Wrap( + children: [ + ElevatedButton( + child: Text("Smaller"), + onPressed: () async { + var size = await DesktopWindow.getWindowSize(); + await DesktopWindow.setWindowSize( + Size(size.width - 50, size.height - 50)); + await _getWindowSize(); + }, + ), + ElevatedButton( + child: Text("Larger"), + onPressed: () async { + var size = await DesktopWindow.getWindowSize(); + await DesktopWindow.setWindowSize( + Size(size.width + 50, size.height + 50)); + await _getWindowSize(); + }, + ), + ], + ), + Wrap( + children: [ + ElevatedButton( + child: Text("toggleFullScreen"), + onPressed: () async { + await DesktopWindow.resetMaxWindowSize(); + await DesktopWindow.toggleFullScreen(); + }, + ), + Builder(builder: (ctx) { + return ElevatedButton( + child: Text("getFullScreen"), + onPressed: () async { + final isFullScreen = + await DesktopWindow.getFullScreen(); + ScaffoldMessenger.of(ctx).showSnackBar(SnackBar( + content: Text('getFullScreen = $isFullScreen'), + duration: Duration(seconds: 1))); + }, + ); + }), + ElevatedButton( + child: Text("setFullScreen(true)"), + onPressed: () async { + await DesktopWindow.setFullScreen(true); + }, + ), + ElevatedButton( + child: Text("setFullScreen(false)"), + onPressed: () async { + await DesktopWindow.setFullScreen(false); + }, + ), + ], + ), + Wrap( + children: [ + ElevatedButton( + child: Text("toggleBorders"), + onPressed: () async { + await DesktopWindow.toggleBorders(); + }, + ), + Builder(builder: (ctx) { + return ElevatedButton( + child: Text("setBorders(true)"), + onPressed: () async { + await DesktopWindow.setBorders(true); + }, + ); + }), + ElevatedButton( + child: Text("setBorders(false)"), + onPressed: () async { + await DesktopWindow.setBorders(false); + }, + ), + ElevatedButton( + child: Text("hasBorders"), + onPressed: () async { + print('hasBorders: ' + + (await DesktopWindow.hasBorders ? 'true' : 'false')); + }, + ), + ], + ), + Wrap( + children: [ + ElevatedButton( + child: Text("focus"), + onPressed: () { + Timer(Duration(seconds: 3), () async { + print('focus!!!'); + await DesktopWindow.focus(); + }); + }, + ), + ElevatedButton( + child: Text("stayOnTop(true)"), + onPressed: () async { + print('stayOnTop(true)'); + await DesktopWindow.stayOnTop(true); + }, + ), + ElevatedButton( + child: Text("stayOnTop(false)"), + onPressed: () async { + print('stayOnTop(false)'); + await DesktopWindow.stayOnTop(false); + }, + ), + ], + ), + ], + ), + ), + ), + ); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/CMakeLists.txt new file mode 100644 index 00000000..77594227 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/CMakeLists.txt @@ -0,0 +1,98 @@ +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +set(BINARY_NAME "desktop_window_example") +set(APPLICATION_ID "com.example.desktop_window") + +cmake_policy(SET CMP0063 NEW) + +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Application build +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) +apply_standard_settings(${BINARY_NAME}) +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/flutter/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..94f43ff7 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/flutter/CMakeLists.txt @@ -0,0 +1,86 @@ +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + linux-x64 ${CMAKE_BUILD_TYPE} +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..321a26bf --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) desktop_window_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopWindowPlugin"); + desktop_window_plugin_register_with_registrar(desktop_window_registrar); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/flutter/generated_plugin_registrant.h b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/flutter/generated_plugins.cmake b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..28296477 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/flutter/generated_plugins.cmake @@ -0,0 +1,16 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + desktop_window +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/main.cc b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/main.cc new file mode 100644 index 00000000..058e6178 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/main.cc @@ -0,0 +1,10 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + // Only X11 is currently supported. + // Wayland support is being developed: https://github.com/flutter/flutter/issues/57932. + gdk_set_allowed_backends("x11"); + + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/my_application.cc b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/my_application.cc new file mode 100644 index 00000000..e6dd5c04 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/my_application.cc @@ -0,0 +1,46 @@ +#include "my_application.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "desktop_window_example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + nullptr)); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/my_application.h b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Flutter/Flutter-Debug.xcconfig b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..785633d3 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Flutter/Flutter-Release.xcconfig b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5fba960c --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Flutter/GeneratedPluginRegistrant.swift b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..070083d2 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,12 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import desktop_window + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + DesktopWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWindowPlugin")) +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Podfile b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Podfile new file mode 100644 index 00000000..d60ec710 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Podfile @@ -0,0 +1,82 @@ +platform :osx, '10.11' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def parse_KV_file(file, separator='=') + file_abs_path = File.expand_path(file) + if !File.exists? file_abs_path + return []; + end + pods_ary = [] + skip_line_start_symbols = ["#", "/"] + File.foreach(file_abs_path) { |line| + next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } + plugin = line.split(pattern=separator) + if plugin.length == 2 + podname = plugin[0].strip() + path = plugin[1].strip() + podpath = File.expand_path("#{path}", file_abs_path) + pods_ary.push({:name => podname, :path => podpath}); + else + puts "Invalid plugin specification: #{line}" + end + } + return pods_ary +end + +def pubspec_supports_macos(file) + file_abs_path = File.expand_path(file) + if !File.exists? file_abs_path + return false; + end + File.foreach(file_abs_path) { |line| + return true if line =~ /^\s*macos:/ + } + return false +end + +target 'Runner' do + use_frameworks! + use_modular_headers! + + # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock + # referring to absolute paths on developers' machines. + ephemeral_dir = File.join('Flutter', 'ephemeral') + symlink_dir = File.join(ephemeral_dir, '.symlinks') + symlink_plugins_dir = File.join(symlink_dir, 'plugins') + system("rm -rf #{symlink_dir}") + system("mkdir -p #{symlink_plugins_dir}") + + # Flutter Pods + generated_xcconfig = parse_KV_file(File.join(ephemeral_dir, 'Flutter-Generated.xcconfig')) + if generated_xcconfig.empty? + puts "Flutter-Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first." + end + generated_xcconfig.map { |p| + if p[:name] == 'FLUTTER_FRAMEWORK_DIR' + symlink = File.join(symlink_dir, 'flutter') + File.symlink(File.dirname(p[:path]), symlink) + pod 'FlutterMacOS', :path => File.join(symlink, File.basename(p[:path])) + end + } + + # Plugin Pods + plugin_pods = parse_KV_file('../.flutter-plugins') + plugin_pods.map { |p| + symlink = File.join(symlink_plugins_dir, p[:name]) + File.symlink(p[:path], symlink) + if pubspec_supports_macos(File.join(symlink, 'pubspec.yaml')) + pod p[:name], :path => File.join(symlink, 'macos') + end + } +end + +# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. +install! 'cocoapods', :disable_input_output_paths => true diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Podfile.lock b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Podfile.lock new file mode 100644 index 00000000..69f85e56 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Podfile.lock @@ -0,0 +1,23 @@ +PODS: + - desktop_window (0.0.1): + - FlutterMacOS + - FlutterMacOS (2.0.0) + +DEPENDENCIES: + - desktop_window (from `Flutter/ephemeral/.symlinks/plugins/desktop_window/macos`) + +SPEC REPOS: + trunk: + - FlutterMacOS + +EXTERNAL SOURCES: + desktop_window: + :path: Flutter/ephemeral/.symlinks/plugins/desktop_window/macos + +SPEC CHECKSUMS: + desktop_window: fb7c4f12c1129f947ac482296b6f14059d57a3c3 + FlutterMacOS: 2f1b456c4d9436c4d4d13919bd3be8ef03ba6322 + +PODFILE CHECKSUM: d8ba9b3e9e93c62c74a660b46c6fcb09f03991a7 + +COCOAPODS: 1.10.1 diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner.xcodeproj/project.pbxproj b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..446bde31 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,642 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 4BA0982C3D6F097DE4C67291 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C82DFC54C86BB48A26A30862 /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 104809D3C7D2B95436B80D2A /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* desktop_window_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = desktop_window_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 799E46E8BBA7DCBEFA0E92BD /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + C82DFC54C86BB48A26A30862 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D7B139BEA3CC563DC273EDEA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4BA0982C3D6F097DE4C67291 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + AFED8D8B5B9C7862813EA647 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* desktop_window_example.app */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + AFED8D8B5B9C7862813EA647 /* Pods */ = { + isa = PBXGroup; + children = ( + D7B139BEA3CC563DC273EDEA /* Pods-Runner.debug.xcconfig */, + 104809D3C7D2B95436B80D2A /* Pods-Runner.release.xcconfig */, + 799E46E8BBA7DCBEFA0E92BD /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + C82DFC54C86BB48A26A30862 /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + E91A418CE0F03238BC861E04 /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 6DE760BC69C42E267332AFAC /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* desktop_window_example.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 0930; + ORGANIZATIONNAME = "The Flutter Authors"; + TargetAttributes = { + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh\ntouch Flutter/ephemeral/tripwire\n"; + }; + 6DE760BC69C42E267332AFAC /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + E91A418CE0F03238BC861E04 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter/ephemeral", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter/ephemeral", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter/ephemeral", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..93470232 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/AppDelegate.swift b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..d53ef643 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..3c4935a7 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..ed4cc164 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..483be613 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bcbf36df Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..9c0a6528 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..e71a7261 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..8a31fe2d Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Base.lproj/MainMenu.xib b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..537341ab --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Configs/AppInfo.xcconfig b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..274b2c2b --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = desktop_window_example + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.mix1009.desktopWindow + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2020 com.mix1009. All rights reserved. diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Configs/Debug.xcconfig b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Configs/Release.xcconfig b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Configs/Warnings.xcconfig b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/DebugProfile.entitlements b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Info.plist b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/MainFlutterWindow.swift b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..2722837e --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController.init() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Release.entitlements b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/pubspec.yaml b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/pubspec.yaml new file mode 100644 index 00000000..eb3dd583 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/pubspec.yaml @@ -0,0 +1,71 @@ +name: desktop_window_example +description: Demonstrates how to use the desktop_window plugin. + +# The following line prevents the package from being accidentally published to +# pub.dev using `pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +environment: + sdk: '>=2.12.0 <3.0.0' + +dependencies: + flutter: + sdk: flutter + + desktop_window: + # When depending on this package from a real application you should use: + # desktop_window: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. + path: ../ + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + +dev_dependencies: + flutter_test: + sdk: flutter + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/CMakeLists.txt new file mode 100644 index 00000000..b60fb4d5 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/CMakeLists.txt @@ -0,0 +1,95 @@ +cmake_minimum_required(VERSION 3.15) +project(desktop_window_example LANGUAGES CXX) + +set(BINARY_NAME "desktop_window_example") + +cmake_policy(SET CMP0063 NEW) + +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() + +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build +add_subdirectory("runner") + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/flutter/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..c7a8c760 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/flutter/CMakeLists.txt @@ -0,0 +1,101 @@ +cmake_minimum_required(VERSION 3.15) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/flutter/generated_plugin_registrant.cc b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..1923f294 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + DesktopWindowPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("DesktopWindowPlugin")); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/flutter/generated_plugin_registrant.h b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/flutter/generated_plugins.cmake b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..c2629e86 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/flutter/generated_plugins.cmake @@ -0,0 +1,16 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + desktop_window +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..977e38b5 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.15) +project(runner LANGUAGES CXX) + +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "run_loop.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) +apply_standard_settings(${BINARY_NAME}) +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/Runner.rc b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/Runner.rc new file mode 100644 index 00000000..80da6bcd --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#ifdef FLUTTER_BUILD_NUMBER +#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER +#else +#define VERSION_AS_NUMBER 1,0,0 +#endif + +#ifdef FLUTTER_BUILD_NAME +#define VERSION_AS_STRING #FLUTTER_BUILD_NAME +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "Demonstrates how to use the desktop_window plugin." "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "desktop_window_example" "\0" + VALUE "LegalCopyright", "Copyright (C) 2020 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "desktop_window_example.exe" "\0" + VALUE "ProductName", "desktop_window_example" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/flutter_window.cpp b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..c4227230 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/flutter_window.cpp @@ -0,0 +1,64 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(RunLoop* run_loop, + const flutter::DartProject& project) + : run_loop_(run_loop), project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + run_loop_->RegisterFlutterInstance(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + run_loop_->UnregisterFlutterInstance(flutter_controller_->engine()); + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opporutunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/flutter_window.h b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/flutter_window.h new file mode 100644 index 00000000..b663ddd5 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/flutter_window.h @@ -0,0 +1,39 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "run_loop.h" +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow driven by the |run_loop|, hosting a + // Flutter view running |project|. + explicit FlutterWindow(RunLoop* run_loop, + const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The run loop driving events for this window. + RunLoop* run_loop_; + + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/main.cpp b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/main.cpp new file mode 100644 index 00000000..9f713b7a --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/main.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "run_loop.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + RunLoop run_loop; + + flutter::DartProject project(L"data"); + FlutterWindow window(&run_loop, project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.CreateAndShow(L"desktop_window_example", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + run_loop.Run(); + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/resource.h b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/resources/app_icon.ico b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/resources/app_icon.ico differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/run_loop.cpp b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/run_loop.cpp new file mode 100644 index 00000000..2d6636ab --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/run_loop.cpp @@ -0,0 +1,66 @@ +#include "run_loop.h" + +#include + +#include + +RunLoop::RunLoop() {} + +RunLoop::~RunLoop() {} + +void RunLoop::Run() { + bool keep_running = true; + TimePoint next_flutter_event_time = TimePoint::clock::now(); + while (keep_running) { + std::chrono::nanoseconds wait_duration = + std::max(std::chrono::nanoseconds(0), + next_flutter_event_time - TimePoint::clock::now()); + ::MsgWaitForMultipleObjects( + 0, nullptr, FALSE, static_cast(wait_duration.count() / 1000), + QS_ALLINPUT); + bool processed_events = false; + MSG message; + // All pending Windows messages must be processed; MsgWaitForMultipleObjects + // won't return again for items left in the queue after PeekMessage. + while (::PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) { + processed_events = true; + if (message.message == WM_QUIT) { + keep_running = false; + break; + } + ::TranslateMessage(&message); + ::DispatchMessage(&message); + // Allow Flutter to process messages each time a Windows message is + // processed, to prevent starvation. + next_flutter_event_time = + std::min(next_flutter_event_time, ProcessFlutterMessages()); + } + // If the PeekMessage loop didn't run, process Flutter messages. + if (!processed_events) { + next_flutter_event_time = + std::min(next_flutter_event_time, ProcessFlutterMessages()); + } + } +} + +void RunLoop::RegisterFlutterInstance( + flutter::FlutterEngine* flutter_instance) { + flutter_instances_.insert(flutter_instance); +} + +void RunLoop::UnregisterFlutterInstance( + flutter::FlutterEngine* flutter_instance) { + flutter_instances_.erase(flutter_instance); +} + +RunLoop::TimePoint RunLoop::ProcessFlutterMessages() { + TimePoint next_event_time = TimePoint::max(); + for (auto instance : flutter_instances_) { + std::chrono::nanoseconds wait_duration = instance->ProcessMessages(); + if (wait_duration != std::chrono::nanoseconds::max()) { + next_event_time = + std::min(next_event_time, TimePoint::clock::now() + wait_duration); + } + } + return next_event_time; +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/run_loop.h b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/run_loop.h new file mode 100644 index 00000000..000d3624 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/run_loop.h @@ -0,0 +1,40 @@ +#ifndef RUNNER_RUN_LOOP_H_ +#define RUNNER_RUN_LOOP_H_ + +#include + +#include +#include + +// A runloop that will service events for Flutter instances as well +// as native messages. +class RunLoop { + public: + RunLoop(); + ~RunLoop(); + + // Prevent copying + RunLoop(RunLoop const&) = delete; + RunLoop& operator=(RunLoop const&) = delete; + + // Runs the run loop until the application quits. + void Run(); + + // Registers the given Flutter instance for event servicing. + void RegisterFlutterInstance( + flutter::FlutterEngine* flutter_instance); + + // Unregisters the given Flutter instance from event servicing. + void UnregisterFlutterInstance( + flutter::FlutterEngine* flutter_instance); + + private: + using TimePoint = std::chrono::steady_clock::time_point; + + // Processes all currently pending messages for registered Flutter instances. + TimePoint ProcessFlutterMessages(); + + std::set flutter_instances_; +}; + +#endif // RUNNER_RUN_LOOP_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/runner.exe.manifest b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..c977c4a4 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/utils.cpp b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/utils.cpp new file mode 100644 index 00000000..37501e5d --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/utils.cpp @@ -0,0 +1,22 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/utils.h b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/utils.h new file mode 100644 index 00000000..d792603b --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/utils.h @@ -0,0 +1,8 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +#endif // RUNNER_UTILS_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/win32_window.cpp b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/win32_window.cpp new file mode 100644 index 00000000..efc3eb9f --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/win32_window.cpp @@ -0,0 +1,244 @@ +#include "win32_window.h" + +#include + +#include "resource.h" + +namespace { + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + FreeLibrary(user32_module); + } +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::CreateAndShow(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + return OnCreate(); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/win32_window.h b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/win32_window.h new file mode 100644 index 00000000..17ba4311 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/example/windows/runner/win32_window.h @@ -0,0 +1,98 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates and shows a win32 window with |title| and position and size using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size to will treat the width height passed in to this function + // as logical pixels and scale to appropriate for the default monitor. Returns + // true if the window was created successfully. + bool CreateAndShow(const std::wstring& title, + const Point& origin, + const Size& size); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responsponds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/lib/desktop_window.dart b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/lib/desktop_window.dart new file mode 100644 index 00000000..416555da --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/lib/desktop_window.dart @@ -0,0 +1,80 @@ +import 'dart:async'; + +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/material.dart'; + +class DesktopWindow { + static const MethodChannel _channel = const MethodChannel('desktop_window'); + + static Future getWindowSize() async { + final arr = await _channel.invokeMethod('getWindowSize'); + if (arr is List && arr.length == 2) { + return Size(arr[0], arr[1]); + } + throw arr; + } + + static Future setWindowSize(Size size, {bool animate = false}) async { + return await _channel.invokeMethod('setWindowSize', + {'width': size.width, 'height': size.height, 'animate': animate}); + } + + static Future setMinWindowSize(Size size) async { + return await _channel.invokeMethod( + 'setMinWindowSize', {'width': size.width, 'height': size.height}); + } + + static Future setMaxWindowSize(Size size) async { + return await _channel.invokeMethod( + 'setMaxWindowSize', {'width': size.width, 'height': size.height}); + } + + static Future resetMaxWindowSize() async { + return await _channel.invokeMethod('resetMaxWindowSize'); + } + + static Future toggleFullScreen() async { + return await _channel.invokeMethod('toggleFullScreen'); + } + + static Future setFullScreen(bool fullscreen) async { + return await _channel + .invokeMethod('setFullScreen', {'fullscreen': fullscreen}); + } + + static Future getFullScreen() async { + final fullscreen = await _channel.invokeMethod('getFullScreen'); + if (fullscreen is bool) return fullscreen; + throw fullscreen; + } + + static Future get hasBorders async { + final hasBorders = await _channel.invokeMethod('hasBorders'); + if (hasBorders is bool) return hasBorders; + throw hasBorders; + } + + static Future toggleBorders() async { + return await _channel.invokeMethod('toggleBorders'); + } + + static Future setBorders(bool border) async { + return await _channel.invokeMethod('setBorders', {'border': border}); + } + + static Future stayOnTop( + [bool stayOnTop = true, bool throwOnUnsupportedPlatform = false]) async { + if (!kIsWeb && (Platform.isWindows || Platform.isLinux || Platform.isMacOS)) + return await _channel.invokeMethod('stayOnTop', {'stayOnTop': stayOnTop}); + else if (throwOnUnsupportedPlatform) + throw UnsupportedError( + "only Linux and Windows support windows staying focused"); + } + + static Future focus() async { + return await _channel.invokeMethod('focus'); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/linux/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/linux/CMakeLists.txt new file mode 100644 index 00000000..812b3d13 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/linux/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.10) +set(PROJECT_NAME "desktop_window") +project(${PROJECT_NAME} LANGUAGES CXX) + +set(PLUGIN_NAME "${PROJECT_NAME}_plugin") + +add_library(${PLUGIN_NAME} SHARED + "${PLUGIN_NAME}.cc" +) +apply_standard_settings(${PLUGIN_NAME}) +set_target_properties(${PLUGIN_NAME} PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) +target_include_directories(${PLUGIN_NAME} INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/include") +target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) +target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) + +# List of absolute paths to libraries that should be bundled with the plugin +set(desktop_window_bundled_libraries + "" + PARENT_SCOPE +) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/linux/desktop_window_plugin.cc b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/linux/desktop_window_plugin.cc new file mode 100644 index 00000000..b8dfdc65 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/linux/desktop_window_plugin.cc @@ -0,0 +1,187 @@ +#include "include/desktop_window/desktop_window_plugin.h" + +#include +#include +#include + +#define DESKTOP_WINDOW_PLUGIN(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), desktop_window_plugin_get_type(), \ + DesktopWindowPlugin)) + +struct _DesktopWindowPlugin +{ + GObject parent_instance; + GtkWidget *widget; +}; + +G_DEFINE_TYPE(DesktopWindowPlugin, desktop_window_plugin, g_object_get_type()) + +// Called when a method call is received from Flutter. +static void desktop_window_plugin_handle_method_call( + DesktopWindowPlugin *self, + FlMethodCall *method_call) +{ + g_autoptr(FlMethodResponse) response = nullptr; + + const gchar *method = fl_method_call_get_name(method_call); + + if (!gtk_widget_is_toplevel(self->widget)) + { + response = FL_METHOD_RESPONSE(fl_method_error_response_new("MAINWINDOW_NOT_FOUND", "GtkWindow not found", fl_value_new_null())); + } + else if (strcmp(method, "getWindowSize") == 0) + { + gint width; + gint height; + + gtk_window_get_size((GtkWindow *)self->widget, &width, &height); + + g_autoptr(FlValue) list = fl_value_new_list(); + fl_value_append_take(list, fl_value_new_float((float)width)); + fl_value_append_take(list, fl_value_new_float((float)height)); + + response = FL_METHOD_RESPONSE(fl_method_success_response_new(list)); + } + else if (strcmp(method, "setWindowSize") == 0) + { + const float width = fl_value_get_float(fl_value_lookup(fl_method_call_get_args(method_call), fl_value_new_string("width"))); + const float height = fl_value_get_float(fl_value_lookup(fl_method_call_get_args(method_call), fl_value_new_string("height"))); + + gtk_window_resize((GtkWindow *)self->widget, (int)width, (int)height); + + response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(true))); + } + else if (strcmp(method, "setMinWindowSize") == 0) + { + const float width = fl_value_get_float(fl_value_lookup(fl_method_call_get_args(method_call), fl_value_new_string("width"))); + const float height = fl_value_get_float(fl_value_lookup(fl_method_call_get_args(method_call), fl_value_new_string("height"))); + + GdkGeometry geometry; + geometry.min_height = (int)height; + geometry.min_width = (int)width; + gdk_window_set_geometry_hints(gtk_widget_get_window(self->widget), &geometry, GDK_HINT_MIN_SIZE); + + response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(true))); + } + else if (strcmp(method, "setMaxWindowSize") == 0) + { + const float width = fl_value_get_float(fl_value_lookup(fl_method_call_get_args(method_call), fl_value_new_string("width"))); + const float height = fl_value_get_float(fl_value_lookup(fl_method_call_get_args(method_call), fl_value_new_string("height"))); + + GdkGeometry geometry; + geometry.max_height = ((int)height) == 0 ? INT_MAX : ((int)height); + geometry.max_width = ((int)width) == 0 ? INT_MAX : ((int)width); + gdk_window_set_geometry_hints(gtk_widget_get_window(self->widget), &geometry, GDK_HINT_MAX_SIZE); + + response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(true))); + } + else if (strcmp(method, "resetMaxWindowSize") == 0) + { + GdkGeometry geometry; + geometry.max_height = INT_MAX; + geometry.max_width = INT_MAX; + gdk_window_set_geometry_hints(gtk_widget_get_window(self->widget), &geometry, GDK_HINT_MAX_SIZE); + + response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(true))); + } + else if (strcmp(method, "toggleFullScreen") == 0) + { + bool isFullscreen = (bool)(gdk_window_get_state(gtk_widget_get_window(self->widget)) & GDK_WINDOW_STATE_FULLSCREEN); + if (!isFullscreen) + gtk_window_fullscreen((GtkWindow *)self->widget); + else + gtk_window_unfullscreen((GtkWindow *)self->widget); + + response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(true))); + } + else if (strcmp(method, "setFullScreen") == 0) + { + bool fullscreen = fl_value_get_bool(fl_value_lookup(fl_method_call_get_args(method_call), fl_value_new_string("fullscreen"))); + + if (fullscreen) + gtk_window_fullscreen((GtkWindow *)self->widget); + else + gtk_window_unfullscreen((GtkWindow *)self->widget); + + response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(true))); + } + else if (strcmp(method, "getFullScreen") == 0) + { + bool isFullscreen = (bool)(gdk_window_get_state(gtk_widget_get_window(self->widget)) & GDK_WINDOW_STATE_FULLSCREEN); + response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(isFullscreen))); + } + else if (strcmp(method, "hasBorders") == 0) + { + bool isDecorated = (bool)gtk_window_get_decorated((GtkWindow *)self->widget); + response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(isDecorated))); + } + else if (strcmp(method, "setBorders") == 0) + { + bool decorated = fl_value_get_bool(fl_value_lookup(fl_method_call_get_args(method_call), fl_value_new_string("border"))); + gtk_window_set_decorated((GtkWindow *)self->widget, decorated); + + response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(true))); + } + else if (strcmp(method, "toggleBorders") == 0) + { + bool isDecorated = (bool)gtk_window_get_decorated((GtkWindow *)self->widget); + gtk_window_set_decorated((GtkWindow *)self->widget, !isDecorated); + + response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(true))); + } + else if (strcmp(method, "focus") == 0) + { + gtk_window_present((GtkWindow *) self->widget); + response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(true))); + } + else if(strcmp(method, "stayOnTop") == 0){ + bool stayOnTop = !fl_value_get_bool(fl_value_lookup(fl_method_call_get_args(method_call), fl_value_new_string("stayOnTop"))); + gdk_window_set_keep_above(gtk_widget_get_window(self->widget), stayOnTop); + response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(true))); + } + + + if (response == nullptr) + response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); + + fl_method_call_respond(method_call, response, nullptr); +} + +static void desktop_window_plugin_dispose(GObject *object) +{ + G_OBJECT_CLASS(desktop_window_plugin_parent_class)->dispose(object); +} + +static void desktop_window_plugin_class_init(DesktopWindowPluginClass *klass) +{ + G_OBJECT_CLASS(klass)->dispose = desktop_window_plugin_dispose; +} + +static void desktop_window_plugin_init(DesktopWindowPlugin *self) {} + +static void method_call_cb(FlMethodChannel *channel, FlMethodCall *method_call, + gpointer user_data) +{ + DesktopWindowPlugin *plugin = DESKTOP_WINDOW_PLUGIN(user_data); + desktop_window_plugin_handle_method_call(plugin, method_call); +} + +void desktop_window_plugin_register_with_registrar(FlPluginRegistrar *registrar) +{ + + GtkWidget *toplevel = gtk_widget_get_toplevel((GtkWidget *)fl_plugin_registrar_get_view(registrar)); + DesktopWindowPlugin *plugin = DESKTOP_WINDOW_PLUGIN( + g_object_new(desktop_window_plugin_get_type(), nullptr)); + plugin->widget = toplevel; + + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + g_autoptr(FlMethodChannel) channel = + fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar), + "desktop_window", + FL_METHOD_CODEC(codec)); + fl_method_channel_set_method_call_handler(channel, method_call_cb, + g_object_ref(plugin), + g_object_unref); + + g_object_unref(plugin); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/linux/include/desktop_window/desktop_window_plugin.h b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/linux/include/desktop_window/desktop_window_plugin.h new file mode 100644 index 00000000..8315b3b8 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/linux/include/desktop_window/desktop_window_plugin.h @@ -0,0 +1,26 @@ +#ifndef FLUTTER_PLUGIN_DESKTOP_WINDOW_PLUGIN_H_ +#define FLUTTER_PLUGIN_DESKTOP_WINDOW_PLUGIN_H_ + +#include + +G_BEGIN_DECLS + +#ifdef FLUTTER_PLUGIN_IMPL +#define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) +#else +#define FLUTTER_PLUGIN_EXPORT +#endif + +typedef struct _DesktopWindowPlugin DesktopWindowPlugin; +typedef struct { + GObjectClass parent_class; +} DesktopWindowPluginClass; + +FLUTTER_PLUGIN_EXPORT GType desktop_window_plugin_get_type(); + +FLUTTER_PLUGIN_EXPORT void desktop_window_plugin_register_with_registrar( + FlPluginRegistrar* registrar); + +G_END_DECLS + +#endif // FLUTTER_PLUGIN_DESKTOP_WINDOW_PLUGIN_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/macos/Classes/DesktopWindowPlugin.swift b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/macos/Classes/DesktopWindowPlugin.swift new file mode 100644 index 00000000..36e1b30f --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/macos/Classes/DesktopWindowPlugin.swift @@ -0,0 +1,135 @@ +import Cocoa +import FlutterMacOS + +public class DesktopWindowPlugin: NSObject, FlutterPlugin { + public static func register(with registrar: FlutterPluginRegistrar) { + let channel = FlutterMethodChannel(name: "desktop_window", binaryMessenger: registrar.messenger) + let instance = DesktopWindowPlugin() + registrar.addMethodCallDelegate(instance, channel: channel) + } + + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + let firstWindow = NSApplication.shared.windows.isEmpty ? nil : NSApplication.shared.windows[0] + if let window = NSApplication.shared.mainWindow ?? firstWindow { + switch call.method { + + case "getWindowSize": + let width = window.frame.size.width + let height = window.frame.size.height + result([width, height]) + + case "setWindowSize": + if let width: Float = (call.arguments as? [String: Any])?["width"] as? Float, + let height: Float = (call.arguments as? [String: Any])?["height"] as? Float, + let animate: Bool = (call.arguments as? [String: Any])?["animate"] as? Bool + { + var rect = window.frame + rect.origin.y += (rect.size.height - CGFloat(height)) + rect.size.width = CGFloat(width) + rect.size.height = CGFloat(height) + + window.animator().setFrame(rect, display: true, animate: animate) + + } + + result(true) + + case "setMinWindowSize": + if let width: Float = (call.arguments as? [String: Any])?["width"] as? Float, + let height: Float = (call.arguments as? [String: Any])?["height"] as? Float + { + window.minSize = CGSize(width: CGFloat(width), height: CGFloat(height)) + + } + + result(true) + + case "setMaxWindowSize": + if let width: Float = (call.arguments as? [String: Any])?["width"] as? Float, + let height: Float = (call.arguments as? [String: Any])?["height"] as? Float + { + if width == 0 || height == 0 { + window.maxSize = CGSize( + width: CGFloat(Float.greatestFiniteMagnitude), + height: CGFloat(Float.greatestFiniteMagnitude)) + } else { + window.maxSize = CGSize(width: CGFloat(width), height: CGFloat(height)) + } + + } + result(true) + + case "resetMaxWindowSize": + window.maxSize = CGSize( + width: CGFloat(Float.greatestFiniteMagnitude), + height: CGFloat(Float.greatestFiniteMagnitude)) + + result(true) + + case "toggleFullScreen": + window.toggleFullScreen(nil) + result(true) + + case "setFullScreen": + if let bFullScreen: Bool = (call.arguments as? [String: Any])?["fullscreen"] as? Bool { + + if bFullScreen { + if !window.styleMask.contains(.fullScreen) { + window.toggleFullScreen(nil) + } + } else { + if window.styleMask.contains(.fullScreen) { + window.toggleFullScreen(nil) + } + } + result(true) + } + + case "getFullScreen": + result(window.styleMask.contains(.fullScreen)) + + case "toggleBorders": + if window.styleMask.contains(.borderless) { + window.styleMask.remove(.borderless) + } else { + window.styleMask.insert(.borderless) + } + result(true) + + case "setBorders": + if let bBorders: Bool = (call.arguments as? [String: Any])?["borders"] as? Bool { + if window.styleMask.contains(.borderless) == bBorders { + if bBorders { + window.styleMask.remove(.borderless) + } else { + window.styleMask.insert(.borderless) + } + } + result(true) + } + + case "hasBorders": + result(!window.styleMask.contains(.borderless)) + + case "focus": + NSApplication.shared.activate(ignoringOtherApps: true) + result(true) + + case "stayOnTop": + if let bstayOnTop: Bool = (call.arguments as? [String: Any])?["stayOnTop"] as? Bool { + if bstayOnTop { + window.level = .floating; + } else { + window.level = .normal; + } + } + result(true) + + default: + result(FlutterMethodNotImplemented) + } + } else { + result("mainWindow not found") // should return error or throw exception here. + } + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/macos/desktop_window.podspec b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/macos/desktop_window.podspec new file mode 100644 index 00000000..ffdf7621 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/macos/desktop_window.podspec @@ -0,0 +1,22 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint desktop_window.podspec' to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'desktop_window' + s.version = '0.0.1' + s.summary = 'A new flutter plugin project.' + s.description = <<-DESC +A new flutter plugin project. + DESC + s.homepage = 'http://example.com' + s.license = { :file => '../LICENSE' } + s.author = { 'Your Company' => 'email@example.com' } + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.dependency 'FlutterMacOS' + + s.platform = :osx, '10.11' + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } + s.swift_version = '5.0' +end diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/pubspec.yaml b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/pubspec.yaml new file mode 100644 index 00000000..0a83e250 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/pubspec.yaml @@ -0,0 +1,34 @@ +name: desktop_window +description: Flutter desktop plugin(macOS/Linux/Windows) to get and change window size. +version: 0.4.2 +#author: ChunKoo Park +homepage: https://github.com/mix1009/desktop_window + + +environment: + sdk: '>=2.12.0 <4.0.0' + flutter: ">=1.20.0" + +dependencies: + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + +flutter: + # This section identifies this Flutter project as a plugin project. + # The 'pluginClass' and Android 'package' identifiers should not ordinarily + # be modified. They are used by the tooling to maintain consistency when + # adding or updating assets for this project. + plugin: + platforms: + macos: + pluginClass: DesktopWindowPlugin + linux: + pluginClass: DesktopWindowPlugin + windows: + pluginClass: DesktopWindowPlugin + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/CMakeLists.txt new file mode 100644 index 00000000..ab52811a --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.15) +set(PROJECT_NAME "desktop_window") +project(${PROJECT_NAME} LANGUAGES CXX) + +set(PLUGIN_NAME "${PROJECT_NAME}_plugin") + +add_library(${PLUGIN_NAME} SHARED + "${PLUGIN_NAME}.cpp" + "include/borders.cpp" + "include/method_call.cpp" +) +apply_standard_settings(${PLUGIN_NAME}) +set_target_properties(${PLUGIN_NAME} PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) +target_include_directories(${PLUGIN_NAME} INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/include") +target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) + +# List of absolute paths to libraries that should be bundled with the plugin +set(desktop_window_bundled_libraries + "" + PARENT_SCOPE +) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/desktop_window_plugin.cpp b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/desktop_window_plugin.cpp new file mode 100644 index 00000000..40c8381e --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/desktop_window_plugin.cpp @@ -0,0 +1,148 @@ +#include "include/desktop_window/desktop_window_plugin.h" + +// This must be included before many other Windows headers. +#include + +// For getPlatformVersion; remove unless needed for your plugin implementation. +#include + +#include +#include +#include + +#include "include/method_call.h" + +#include +#include +#include + +namespace +{ + + LRESULT CALLBACK MyWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam); + WNDPROC oldProc; + + int maxWidth = 0; + int maxHeight = 0; + int minWidth = 0; + int minHeight = 0; + + class DesktopWindowPlugin : public flutter::Plugin + { + public: + static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar); + + DesktopWindowPlugin(); + + virtual ~DesktopWindowPlugin(); + + private: + // Called when a method is called on this plugin's channel from Dart. + void HandleMethodCall( + const flutter::MethodCall &method_call, + std::unique_ptr> result); + }; + + // static + void DesktopWindowPlugin::RegisterWithRegistrar( + flutter::PluginRegistrarWindows *registrar) + { + auto channel = + std::make_unique>( + registrar->messenger(), "desktop_window", + &flutter::StandardMethodCodec::GetInstance()); + + auto plugin = std::make_unique(); + + channel->SetMethodCallHandler( + [plugin_pointer = plugin.get()](const auto &call, auto result) + { + plugin_pointer->HandleMethodCall(call, std::move(result)); + }); + + registrar->AddPlugin(std::move(plugin)); + + HWND handle = GetActiveWindow(); + oldProc = reinterpret_cast(GetWindowLongPtr(handle, GWLP_WNDPROC)); + SetWindowLongPtr(handle, GWLP_WNDPROC, (LONG_PTR)MyWndProc); + } + + DesktopWindowPlugin::DesktopWindowPlugin() {} + + DesktopWindowPlugin::~DesktopWindowPlugin() {} + + + void DesktopWindowPlugin::HandleMethodCall(const flutter::MethodCall &method_call, + std::unique_ptr> result) + { + DesktopWindowMethodCall::MethodCall methodCall(method_call, std::move(result)); + + const std::string method_name = method_call.method_name(); + if (method_name == "getWindowSize") + methodCall.getWindowSize(); + else if (method_name == "setWindowSize") + methodCall.setWindowSize(); + else if (method_name == "setFullScreen") + methodCall.setFullscreen(); + else if (method_name == "getFullScreen") + methodCall.getFullscreen(); + else if (method_name == "toggleFullScreen") + methodCall.toggleFullscreen(); + else if (method_name == "setBorders") + methodCall.setBorders(); + else if (method_name == "hasBorders") + methodCall.hasBorders(); + else if (method_name == "toggleBorders") + methodCall.toggleBorders(); + else if (method_name == "resetMaxWindowSize") + methodCall.resetMaxWindowSize(maxWidth, maxHeight); + else if (method_name == "setMinWindowSize") + methodCall.setMinWindowSize(minWidth, minHeight); + else if (method_name == "setMaxWindowSize") + methodCall.setMaxWindowSize(maxWidth, maxHeight); + else if (method_name == "stayOnTop") + methodCall.stayOnTop(); + else if (method_name == "focus") + methodCall.focus(); + else + result->NotImplemented(); + } + + LRESULT CALLBACK MyWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) + { + if (iMessage == WM_GETMINMAXINFO) + { + // OutputDebugString(L"WM_GETMINMAXINFO called"); + + bool changed = false; + + if (maxWidth != 0 && maxHeight != 0) + { + ((MINMAXINFO *)lParam)->ptMaxTrackSize.x = maxWidth; + ((MINMAXINFO *)lParam)->ptMaxTrackSize.y = maxHeight; + changed = true; + } + if (minWidth != 0 && minHeight != 0) + { + ((MINMAXINFO *)lParam)->ptMinTrackSize.x = minWidth; + ((MINMAXINFO *)lParam)->ptMinTrackSize.y = minHeight; + changed = true; + } + if (changed) + { + return FALSE; + } + } + + return oldProc(hWnd, iMessage, wParam, lParam); + } + +} // namespace + +void DesktopWindowPluginRegisterWithRegistrar( + FlutterDesktopPluginRegistrarRef registrar) +{ + DesktopWindowPlugin::RegisterWithRegistrar( + flutter::PluginRegistrarManager::GetInstance() + ->GetRegistrar(registrar)); +} \ No newline at end of file diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/include/borders.cpp b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/include/borders.cpp new file mode 100644 index 00000000..b3c37798 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/include/borders.cpp @@ -0,0 +1,66 @@ +#include "borders.h" + +namespace Borders +{ + long borderStyle = NULL; + + const long mapWS_SM(const long *changes, long WS, long SM) + { + return ((*changes & WS) > 0) * GetSystemMetrics(SM); + } + + bool hasBorders(HWND *hWnd) + { + return (GetWindowLong(*hWnd, GWL_STYLE) & WINDOW_BORDERS) != 0; + } + + void setBorders(HWND *hWnd, bool borders, bool changeThickFrame) + { + if (hasBorders(hWnd) == borders) + return; + + RECT rect; + GetWindowRect(*hWnd, &rect); + + long currentStyle = GetWindowLong(*hWnd, GWL_STYLE); + if (borderStyle == NULL) + borderStyle = currentStyle & (WINDOW_BORDERS | WS_THICKFRAME); + + const long lastStyle = currentStyle; + + if (borders) + currentStyle |= borderStyle & (WINDOW_BORDERS | (changeThickFrame * WS_THICKFRAME)); + else + currentStyle &= ~(WINDOW_BORDERS | (changeThickFrame * WS_THICKFRAME)); + + SetWindowLong(*hWnd, GWL_STYLE, currentStyle); + + const long diff = lastStyle ^ currentStyle; + + const short op = 2 * borders - 1; // gets borders = 1, looses borders = -1 + + const long xBorder = + mapWS_SM(&diff, WS_THICKFRAME, SM_CXSIZEFRAME) + + mapWS_SM(&diff, WS_BORDER, SM_CXBORDER) + + mapWS_SM(&diff, WS_DLGFRAME, SM_CXDLGFRAME); + const long yBorder = + mapWS_SM(&diff, WS_THICKFRAME, SM_CYSIZEFRAME) + + mapWS_SM(&diff, WS_BORDER, SM_CYBORDER) + + mapWS_SM(&diff, WS_DLGFRAME, SM_CYDLGFRAME); + + const long caption = mapWS_SM(&diff, WS_CAPTION & ~WS_BORDER, SM_CYCAPTION); + + const long xPos = rect.left - (op * xBorder); + const long yPos = rect.top - (op * yBorder) - (op * caption); + const long width = rect.right - rect.left + (2 * op * xBorder); + const long height = rect.bottom - rect.top + (2 * op * yBorder) + (op * caption); + + SetWindowPos(*hWnd, HWND_TOP, xPos, yPos, width, height, SWP_SHOWWINDOW); + } + + void toggleBorders(HWND *hWnd, bool changeThickframe) + { + setBorders(hWnd, !hasBorders(hWnd), changeThickframe); + } + +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/include/borders.h b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/include/borders.h new file mode 100644 index 00000000..c68912ef --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/include/borders.h @@ -0,0 +1,20 @@ +#ifndef FLUTTER_PLUGIN_DESKTOP_WINDOW_PLUGIN_WINDOW_BORDERS_ +#define FLUTTER_PLUGIN_DESKTOP_WINDOW_PLUGIN_WINDOW_BORDERS_ + +#include + +#define WINDOW_BORDERS (WS_BORDER | WS_CAPTION | WS_DLGFRAME) + +namespace Borders +{ + + extern long borderStyle; + + const long mapWS_SM(const long *changes, long WS, long SM); + + bool hasBorders(HWND *hWnd); + void setBorders(HWND *hWnd, bool borders, bool changeThickFrame = false); + void toggleBorders(HWND *hWnd, bool changeThickframe = false); +} + +#endif // FLUTTER_PLUGIN_DESKTOP_WINDOW_PLUGIN_WINDOW_BORDERS_ \ No newline at end of file diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/include/desktop_window/desktop_window_plugin.h b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/include/desktop_window/desktop_window_plugin.h new file mode 100644 index 00000000..3f84e799 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/include/desktop_window/desktop_window_plugin.h @@ -0,0 +1,24 @@ +#ifndef FLUTTER_PLUGIN_DESKTOP_WINDOW_PLUGIN_H_ +#define FLUTTER_PLUGIN_DESKTOP_WINDOW_PLUGIN_H_ + +#include + +#ifdef FLUTTER_PLUGIN_IMPL +#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) +#endif + +#if defined(__cplusplus) +extern "C" +{ +#endif + + FLUTTER_PLUGIN_EXPORT void DesktopWindowPluginRegisterWithRegistrar( + FlutterDesktopPluginRegistrarRef registrar); + +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif // FLUTTER_PLUGIN_DESKTOP_WINDOW_PLUGIN_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/include/method_call.cpp b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/include/method_call.cpp new file mode 100644 index 00000000..cf7c24a0 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/include/method_call.cpp @@ -0,0 +1,260 @@ +#include "method_call.h" +#include "borders.h" + +namespace DesktopWindowMethodCall +{ + + MethodCall::MethodCall(const flutter::MethodCall &Cmethod_call, + std::unique_ptr> Cresult): method_call(Cmethod_call) + { + result = std::move(Cresult); + } + + void MethodCall::setFullscreen() + { + const auto *arguments = std::get_if(method_call.arguments()); + bool fullscreen = false; + if (arguments) + { + auto fs_it = arguments->find(flutter::EncodableValue("fullscreen")); + if (fs_it != arguments->end()) + { + fullscreen = std::get(fs_it->second); + } + } + HWND handle = GetActiveWindow(); + + WINDOWPLACEMENT placement; + + GetWindowPlacement(handle, &placement); + + if (fullscreen) + { + placement.showCmd = SW_MAXIMIZE; + SetWindowPlacement(handle, &placement); + } + else + { + placement.showCmd = SW_NORMAL; + SetWindowPlacement(handle, &placement); + } + + result->Success(flutter::EncodableValue(true)); + } + + void MethodCall::getFullscreen() + { + HWND handle = GetActiveWindow(); + + WINDOWPLACEMENT placement; + GetWindowPlacement(handle, &placement); + + result->Success(flutter::EncodableValue(placement.showCmd == SW_MAXIMIZE)); + } + + void MethodCall::toggleFullscreen() + { + HWND handle = GetActiveWindow(); + + WINDOWPLACEMENT placement; + GetWindowPlacement(handle, &placement); + + if (placement.showCmd == SW_MAXIMIZE) + { + placement.showCmd = SW_NORMAL; + SetWindowPlacement(handle, &placement); + } + else + { + placement.showCmd = SW_MAXIMIZE; + SetWindowPlacement(handle, &placement); + } + result->Success(flutter::EncodableValue(true)); + } + + void MethodCall::setBorders() + { + const auto *arguments = std::get_if(method_call.arguments()); + bool border = false; + if (arguments) + { + auto fs_it = arguments->find(flutter::EncodableValue("border")); + if (fs_it != arguments->end()) + { + border = std::get(fs_it->second); + } + } + + HWND hWnd = GetActiveWindow(); + + Borders::setBorders(&hWnd, border, true); + + result->Success(flutter::EncodableValue(true)); + } + + void MethodCall::hasBorders() + { + HWND hWnd = GetActiveWindow(); + result->Success(flutter::EncodableValue(Borders::hasBorders(&hWnd))); + } + + void MethodCall::toggleBorders() + { + HWND hWnd = GetActiveWindow(); + Borders::toggleBorders(&hWnd, true); + + result->Success(flutter::EncodableValue(true)); + } + + void MethodCall::stayOnTop() + { + const auto *arguments = std::get_if(method_call.arguments()); + bool stayOnTop = false; + if (arguments) + { + auto fs_it = arguments->find(flutter::EncodableValue("stayOnTop")); + if (fs_it != arguments->end()) + { + stayOnTop = std::get(fs_it->second); + } + } + + HWND hWnd = GetActiveWindow(); + + RECT rect; + GetWindowRect(hWnd, &rect); + SetWindowPos(hWnd, stayOnTop? HWND_TOPMOST: HWND_NOTOPMOST, rect.left, rect.top, rect.right-rect.left, rect.bottom -rect.top, SWP_SHOWWINDOW); + + result->Success(flutter::EncodableValue(true)); + } + + + void MethodCall::focus() + { + HWND hWnd = GetActiveWindow(); + SetFocus(hWnd); + + result->Success(flutter::EncodableValue(true)); + } + + void MethodCall::getWindowSize() { + HWND hwnd = GetActiveWindow(); + if (!hwnd) { + result->Error("WINDOW_ERROR", "Unable to get active window."); + return; + } + + RECT rect; + GetWindowRect(hwnd, &rect); + + LONG lWidth = rect.right - rect.left; + LONG lHeight = rect.bottom - rect.top; + + double width = lWidth * 1.0f; + double height = lHeight * 1.0f; + + result->Success(flutter::EncodableValue(flutter::EncodableList{flutter::EncodableValue(width), flutter::EncodableValue(height)})); + } + + void MethodCall::setWindowSize() { + double width = 0; + double height = 0; + const auto *arguments = std::get_if(method_call.arguments()); + if (arguments) + { + auto width_it = arguments->find(flutter::EncodableValue("width")); + if (width_it != arguments->end()) + { + width = std::get(width_it->second); + } + auto height_it = arguments->find(flutter::EncodableValue("height")); + if (height_it != arguments->end()) + { + height = std::get(height_it->second); + } + } + if (width == 0 || height == 0) + { + result->Error("argument_error", "width or height not provided"); + return; + } + + HWND handle = GetActiveWindow(); + + int iWidth = int(width + 0.5); + int iHeight = int(height + 0.5); + + SetWindowPos(handle, HWND_TOP, 0, 0, iWidth, iHeight, SWP_NOMOVE); + + result->Success(flutter::EncodableValue(true)); + } + + void MethodCall::resetMaxWindowSize(int &maxWidth, int &maxHeight) + { + maxWidth = 0; + maxHeight = 0; + + result->Success(flutter::EncodableValue(true)); + } + + void MethodCall::setMinWindowSize(int &minWidth, int &minHeight) + { + double width = 0; + double height = 0; + const auto *arguments = std::get_if(method_call.arguments()); + if (arguments) + { + auto width_it = arguments->find(flutter::EncodableValue("width")); + if (width_it != arguments->end()) + { + width = std::get(width_it->second); + } + auto height_it = arguments->find(flutter::EncodableValue("height")); + if (height_it != arguments->end()) + { + height = std::get(height_it->second); + } + } + if (width == 0 || height == 0) + { + result->Error("argument_error", "width or height not provided"); + return; + } + + minWidth = int(width + 0.5); + minHeight = int(height + 0.5); + + result->Success(flutter::EncodableValue(true)); + } + + void MethodCall::setMaxWindowSize(int &maxWidth, int &maxHeight) + { + double width = 0; + double height = 0; + const auto *arguments = std::get_if(method_call.arguments()); + if (arguments) + { + auto width_it = arguments->find(flutter::EncodableValue("width")); + if (width_it != arguments->end()) + { + width = std::get(width_it->second); + } + auto height_it = arguments->find(flutter::EncodableValue("height")); + if (height_it != arguments->end()) + { + height = std::get(height_it->second); + } + } + if (width == 0 || height == 0) + { + result->Error("argument_error", "width or height not provided"); + return; + } + + maxWidth = int(width + 0.5); + maxHeight = int(height + 0.5); + + result->Success(flutter::EncodableValue(true)); + } + +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/include/method_call.h b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/include/method_call.h new file mode 100644 index 00000000..5c2f3943 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/desktop_window/windows/include/method_call.h @@ -0,0 +1,37 @@ +#ifndef FLUTTER_PLUGIN_DESKTOP_WINDOW_PLUGIN_WINDOW_METHOD_CALL_ +#define FLUTTER_PLUGIN_DESKTOP_WINDOW_PLUGIN_WINDOW_METHOD_CALL_ + +#include +#include +#include +#include + +namespace DesktopWindowMethodCall +{ + class MethodCall + { + public: + MethodCall(const flutter::MethodCall &Cmethod_call, + std::unique_ptr> Cresult); + + void setFullscreen(); + void getFullscreen(); + void toggleFullscreen(); + void setBorders(); + void hasBorders(); + void toggleBorders(); + void stayOnTop(); + void focus(); + void getWindowSize(); + void setWindowSize(); + void resetMaxWindowSize(int &maxWidth, int &maxHeight); + void setMinWindowSize(int &minWidth, int &minHeight); + void setMaxWindowSize(int &maxWidth, int &maxHeight); + + private: + const flutter::MethodCall &method_call; + std::unique_ptr> result; + }; +} + +#endif // FLUTTER_PLUGIN_DESKTOP_WINDOW_PLUGIN_WINDOW_METHOD_CALL_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/CHANGELOG.md b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/CHANGELOG.md new file mode 100644 index 00000000..2e2d918a --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/CHANGELOG.md @@ -0,0 +1,524 @@ +## 12.3.0 + + - **FEAT**(device_info_plus): Add identifiers for iPad Pro 11-Inch (M5) models ([#3708](https://github.com/fluttercommunity/plus_plugins/issues/3708)). ([61786a1d](https://github.com/fluttercommunity/plus_plugins/commit/61786a1d680d8c3886b4fceb34d689ec94e10d8a)) + +## 12.2.0 + + - **FIX**(device_info_plus): correct Mac model name mappings ([#3690](https://github.com/fluttercommunity/plus_plugins/issues/3690)). ([5040a78e](https://github.com/fluttercommunity/plus_plugins/commit/5040a78e26e2abbc9b9e1e8cbb23b1e6e38ad32a)) + - **FEAT**(device_info_plus): Add missing device identifiers for Macs on M4 ([#3700](https://github.com/fluttercommunity/plus_plugins/issues/3700)). ([b4dbd144](https://github.com/fluttercommunity/plus_plugins/commit/b4dbd1444c3104bc1f10af941907905d3070edcf)) + - **FEAT**(device_info_plus): Add identifiers for new Apple devices on M5 chip ([#3698](https://github.com/fluttercommunity/plus_plugins/issues/3698)). ([4cc3f07f](https://github.com/fluttercommunity/plus_plugins/commit/4cc3f07fd4836e5417089630439fcb8a9cdb6bf5)) + +## 12.1.0 + + - **FEAT**(device_info_plus): add mapping for new iPhone 17 series models ([#3676](https://github.com/fluttercommunity/plus_plugins/issues/3676)). ([80eb9815](https://github.com/fluttercommunity/plus_plugins/commit/80eb98156aed96fbc214736964724604e9c80b4f)) + +## 12.0.0 + +> Note: This release has breaking changes. +> +> Plugin now requires the following: +> - Android Gradle Plugin >=8.12.1 +> - Gradle wrapper >=8.13 +> - Kotlin 2.2.0 + + - **DOCS**(all): replace MacOS by macOS in package READMEs ([#3658](https://github.com/fluttercommunity/plus_plugins/issues/3658)). ([72b6234c](https://github.com/fluttercommunity/plus_plugins/commit/72b6234c25315c30d8efc9f15a9258b0bb7273a8)) + - **BREAKING** **REFACTOR**(device_info_plus): remove `serialNumber` property from AndroidDeviceInfo ([#3663](https://github.com/fluttercommunity/plus_plugins/issues/3663)). ([d0fdc582](https://github.com/fluttercommunity/plus_plugins/commit/d0fdc582e8187f71522678e19b6329221b5f535d)) + - **BREAKING** **FEAT**(device_info_plus): Change Android compile SDK, update Android build config ([#3668](https://github.com/fluttercommunity/plus_plugins/issues/3668)). ([32528e7f](https://github.com/fluttercommunity/plus_plugins/commit/32528e7f852893dd4448c448096e459e1950c7e4)) + +## 11.5.0 + + - **FIX**(device_info_plus): Specify correct Dart and Flutter version requirements ([#3597](https://github.com/fluttercommunity/plus_plugins/issues/3597)). ([6ebc0ead](https://github.com/fluttercommunity/plus_plugins/commit/6ebc0ead68df477f06c6d4738a69a9e56223cf47)) + - **FEAT**(device_info_plus): Add identifier for iPhone 16e ([#3596](https://github.com/fluttercommunity/plus_plugins/issues/3596)). ([e1152bb8](https://github.com/fluttercommunity/plus_plugins/commit/e1152bb87d702ff86aaf29e9b7362d8dfd3247e0)) + - **FEAT**(device_info_plus): Add storage information ([#3536](https://github.com/fluttercommunity/plus_plugins/issues/3536)). ([fefe6ce7](https://github.com/fluttercommunity/plus_plugins/commit/fefe6ce7a04c01c39f0cf0ecd0855bce1d701883)) + +## 11.4.0 + + - **FEAT**(device_info_plus): add ram information ([#3535](https://github.com/fluttercommunity/plus_plugins/issues/3535)). ([160a0182](https://github.com/fluttercommunity/plus_plugins/commit/160a01824cb8a245aec52eb3f5a1fa804ef791eb)) + - **FEAT**(device_info_plus): allow to mock device info ([#3525](https://github.com/fluttercommunity/plus_plugins/issues/3525)). ([f78f32c4](https://github.com/fluttercommunity/plus_plugins/commit/f78f32c47fef8045f34944899f6082303182b615)) + +## 11.3.3 + + - **FIX**(device_info_plus): handle nullability on getString(DEVICE_NAME) ([#3507](https://github.com/fluttercommunity/plus_plugins/issues/3507)). ([3201e056](https://github.com/fluttercommunity/plus_plugins/commit/3201e056b2a44ce74a3a9218fba59d71d9795379)) + +## 11.3.2 + +**Note:** This release bumps dependency `win32_registry` from `1.1.5` to `2.0.1`. It will not compile if you have Dependency Overrides for that package. + + - **FIX**(device_info_plus): tighten dependency constraints ([#3497](https://github.com/fluttercommunity/plus_plugins/issues/3497)). ([c7e2428a](https://github.com/fluttercommunity/plus_plugins/commit/c7e2428a6075df4e37da9ef4934861c7cb0c3bee)) + - **FIX**(device_info_plus): fix memory leak when calling DeviceInfoPlugin().macOsInfo ([#3474](https://github.com/fluttercommunity/plus_plugins/issues/3474)). ([1cbf2b56](https://github.com/fluttercommunity/plus_plugins/commit/1cbf2b5621465456221b50ade7ac6c2f3266788d)) + +## 11.3.1 + +- Retracted release due to [#3496](https://github.com/fluttercommunity/plus_plugins/issues/3496) + +## 11.3.0 + + - **FEAT**(device_info_plus): Add User Device Name in Android (PR [#3437](https://github.com/fluttercommunity/plus_plugins/issues/3437)) ([#3456](https://github.com/fluttercommunity/plus_plugins/issues/3456)). ([8c38a31d](https://github.com/fluttercommunity/plus_plugins/commit/8c38a31d7c1073d7011ec3e3193f6b99b3851ef1)) + +## 11.2.2 + + - **FIX**(device_info_plus): Replace throwing exception with returning default values on Windows ([#3445](https://github.com/fluttercommunity/plus_plugins/issues/3445)). ([084730f8](https://github.com/fluttercommunity/plus_plugins/commit/084730f82436b474b31b16f6dc2d7b90585e899f)) + - **DOCS**(device_info_plus): Update the documentation URL for property descriptions. ([#3441](https://github.com/fluttercommunity/plus_plugins/issues/3441)). ([743bec62](https://github.com/fluttercommunity/plus_plugins/commit/743bec626c909fdc8ba6d087006568cca60563d8)) + +## 11.2.1 + + - **FIX**(device_info_plus): Resolve compilation issues with SPM enabled ([#3405](https://github.com/fluttercommunity/plus_plugins/issues/3405)). ([3f098c30](https://github.com/fluttercommunity/plus_plugins/commit/3f098c30320e1595c06b093e8eb9827a44435c5d)) + - **FIX**(device_info_plus): device memory null error on Safari and Firefox ([#3401](https://github.com/fluttercommunity/plus_plugins/issues/3401)). ([2b7cb088](https://github.com/fluttercommunity/plus_plugins/commit/2b7cb0888cd725dc69e409590861fe8118058c4d)) + - **FIX**(device_info_plus): add @Suppress(deprecate) to Build.SERIAL ([#3402](https://github.com/fluttercommunity/plus_plugins/issues/3402)). ([8e70d3f3](https://github.com/fluttercommunity/plus_plugins/commit/8e70d3f33d5f1c005dbb1aef733a8a8578989bac)) + +## 11.2.0 + + - **REFACTOR**(all): Use range of flutter_lints for broader compatibility ([#3371](https://github.com/fluttercommunity/plus_plugins/issues/3371)). ([8a303add](https://github.com/fluttercommunity/plus_plugins/commit/8a303add3dee1acb8bac5838246490ed8a0fe408)) + - **FIX**(device_info_plus): fix the error in the e2e test. ([#3382](https://github.com/fluttercommunity/plus_plugins/issues/3382)). ([3d06bf0e](https://github.com/fluttercommunity/plus_plugins/commit/3d06bf0ed8f1029df1230e4be6e75537abfcb19f)) + - **FIX**(device_info_plus): Set correct Flutter and Dart versions requirements ([#3362](https://github.com/fluttercommunity/plus_plugins/issues/3362)). ([77861523](https://github.com/fluttercommunity/plus_plugins/commit/778615231c376c829d6241e7988f15a77bcaeb55)) + - **FEAT**(device_info_plus): Return model name for iOS and MacOS devices ([#3358](https://github.com/fluttercommunity/plus_plugins/issues/3358)). ([63ca4cd8](https://github.com/fluttercommunity/plus_plugins/commit/63ca4cd8127e010650468a79532dd3a6047d2b31)) + - **FEAT**(device_info_plus): Add the isiOSAppOnMac property for the iOS platform. ([#3383](https://github.com/fluttercommunity/plus_plugins/issues/3383)). ([e9077845](https://github.com/fluttercommunity/plus_plugins/commit/e9077845342023d325280985234b6a09d245ac02)) + +## 11.1.1 + + - **FIX**(device_info_plus): Update privacy manifest paths ([#3347](https://github.com/fluttercommunity/plus_plugins/issues/3347)). ([46df2302](https://github.com/fluttercommunity/plus_plugins/commit/46df23023a5ba6c98edd31d5fd06bec5df40bd3b)) + +## 11.1.0 + + - **FIX**(device_info_plus): Ignore `MissingPermission` lint error on Android ([#3317](https://github.com/fluttercommunity/plus_plugins/issues/3317)). ([6469523f](https://github.com/fluttercommunity/plus_plugins/commit/6469523fb14f32f7aa23892183693a8f502992d3)) + - **FEAT**(device_info_plus): Add Swift Package Manager support ([#3167](https://github.com/fluttercommunity/plus_plugins/issues/3167)). ([6a347cb1](https://github.com/fluttercommunity/plus_plugins/commit/6a347cb106182d68329cd32827938e26bc7e7b00)) + +## 11.0.0 + +> Note: This release has breaking changes. + + - **FIX**(all): Clean up macOS Privacy Manifests ([#3268](https://github.com/fluttercommunity/plus_plugins/issues/3268)). ([d7b98ebd](https://github.com/fluttercommunity/plus_plugins/commit/d7b98ebd7d39b0143931f5cc6e627187576223dc)) + - **FIX**(all): Add macOS Privacy Manifests ([#3251](https://github.com/fluttercommunity/plus_plugins/issues/3251)). ([bf5dad2a](https://github.com/fluttercommunity/plus_plugins/commit/bf5dad2ad249605055bcbd5f663e42569df12d64)) + - **FIX**(device_info_plus): Fix type cast of digitalProductId on windows ([#3188](https://github.com/fluttercommunity/plus_plugins/issues/3188)). ([91f48a6b](https://github.com/fluttercommunity/plus_plugins/commit/91f48a6bc7d11c4238c9539ca06e6fa768995580)) + - **BREAKING** **FIX**(device_info_plus): fixed webasm compliance ([#3254](https://github.com/fluttercommunity/plus_plugins/issues/3254)). ([e35e2123](https://github.com/fluttercommunity/plus_plugins/commit/e35e2123451fc103bbb6f6d94f71ebced2ae8af5)) + +## 10.1.2 + + - **DOCS**(device_info_plus): Update plugin requirements in README ([#3162](https://github.com/fluttercommunity/plus_plugins/issues/3162)). ([6cfa950f](https://github.com/fluttercommunity/plus_plugins/commit/6cfa950f66fec649093b6c44755dc06a3a23319e)) + +## 10.1.1 + + - **CHORE**(device_info_plus): Use `>=0.5.0 < 2.0.0` version range for package:web. + - **FIX**(device_info_plus): fix integration_test iOS ([#2958](https://github.com/fluttercommunity/plus_plugins/issues/2958)). ([93ab854e](https://github.com/fluttercommunity/plus_plugins/commit/93ab854ee76a3de48387b6c54ddaeccb01cf49a9)) + - **REFACTOR**(all): Remove website files, configs, mentions ([#3018](https://github.com/fluttercommunity/plus_plugins/issues/3018)). ([ecc57146](https://github.com/fluttercommunity/plus_plugins/commit/ecc57146aa8c6b1c9c332169d3cc2205bc4a700f)) + - **FIX**(all): changed homepage url in pubspec.yaml ([#3099](https://github.com/fluttercommunity/plus_plugins/issues/3099)). ([66613656](https://github.com/fluttercommunity/plus_plugins/commit/66613656a85c176ba2ad337e4d4943d1f4171129)) + +## 10.1.0 + + - **REFACTOR**(device_info_plus): Migrate Android example to use the new plugins declaration ([#2769](https://github.com/fluttercommunity/plus_plugins/issues/2769)). ([6103b155](https://github.com/fluttercommunity/plus_plugins/commit/6103b1559d6f9383bd66460bf7717afeeeb51d86)) + - **FIX**(device_info_plus): WASM-compatible conditional imports ([#2826](https://github.com/fluttercommunity/plus_plugins/issues/2826)). ([11200cf4](https://github.com/fluttercommunity/plus_plugins/commit/11200cf4eb38bfa6bc83e955a3ceff7b8fc72493)) + - **FEAT**(device_info_plus): Add isLowRamDevice property to AndroidDeviceInfo ([#2765](https://github.com/fluttercommunity/plus_plugins/issues/2765)). ([1376b035](https://github.com/fluttercommunity/plus_plugins/commit/1376b0359fd39172cfb54595178313c73f5d1942)) + - **DOCS**(device_info_plus): Add iOS name property entitlements info ([#2756](https://github.com/fluttercommunity/plus_plugins/issues/2756)). ([d21f285a](https://github.com/fluttercommunity/plus_plugins/commit/d21f285a1d26e7a512c4a9aea579de9680a6ca48)) + +## 10.0.1 + +> Note: This release has breaking changes. + +In this release plugin migrated to package:web, meaning that it now supports WASM! + +Plugin now requires the following: +- Flutter >=3.19.0 +- Dart >=3.3.0 +- compileSDK 34 for Android part +- Java 17 for Android part +- Gradle 8.4 for Android part +- + - **BREAKING** **REFACTOR**(device_info_plus): bump MACOSX_DEPLOYMENT_TARGET from 10.11 to 10.14 ([#2589](https://github.com/fluttercommunity/plus_plugins/issues/2589)). ([1c586abf](https://github.com/fluttercommunity/plus_plugins/commit/1c586abf7ee351927242a70cb88e2e36140cec9e)) + - **BREAKING** **FIX**(device_info_plus): Remove Display Metrics from Android Device Info ([#2731](https://github.com/fluttercommunity/plus_plugins/issues/2731)). ([c5af3322](https://github.com/fluttercommunity/plus_plugins/commit/c5af332207e44902ac92765da72d2acb213fae91)) + - **BREAKING** **FEAT**(device_info_plus): migrate to package:web ([#2624](https://github.com/fluttercommunity/plus_plugins/issues/2624)). ([154e76ca](https://github.com/fluttercommunity/plus_plugins/commit/154e76ca2f9e8c1ccdaa6e2076426002c9d372a3)) + - **BREAKING** **BUILD**(device_info_plus): Target Java 17 on Android ([#2725](https://github.com/fluttercommunity/plus_plugins/issues/2725)). ([aa826dea](https://github.com/fluttercommunity/plus_plugins/commit/aa826deac5ef8136ce922f5823be2e7f90f828e9)) + - **BREAKING** **BUILD**(device_info_plus): Update to target and compile SDK 34 ([#2704](https://github.com/fluttercommunity/plus_plugins/pull/2704)). ([a3cd72f](https://github.com/fluttercommunity/plus_plugins/commit/a3cd72f86ba47f43c507f8b83f89aac7519404de)) + - **FIX**(device_info_plus): remove unnecessary print ([#2607](https://github.com/fluttercommunity/plus_plugins/issues/2607)). ([5d515816](https://github.com/fluttercommunity/plus_plugins/commit/5d5158169f75c50f15588c10e07af2e25f950c23)) + - **FIX**(device_info_plus): return type of isPhysicalDevice as boolean for ios ([#2508](https://github.com/fluttercommunity/plus_plugins/issues/2508)). ([e3a983bb](https://github.com/fluttercommunity/plus_plugins/commit/e3a983bbf0b0bb70c7c50835ddb7f3c4a46b7122)) + - **FIX**(device_info_plus): Add iOS Privacy Info ([#2582](https://github.com/fluttercommunity/plus_plugins/issues/2582)). ([34fe31eb](https://github.com/fluttercommunity/plus_plugins/commit/34fe31eb29e21fa9ea336e61d8df6858eb441a00)) + - **FEAT**(device_info_plus): Update min iOS target to 12 ([#2658](https://github.com/fluttercommunity/plus_plugins/issues/2658)). ([a3436100](https://github.com/fluttercommunity/plus_plugins/commit/a3436100fabd04a4d4db7ac09128b5b5962579d3)) + - **FEAT**(device_info_plus): LinuxDeviceInfo toString method ([#2652](https://github.com/fluttercommunity/plus_plugins/issues/2652)). ([f2fbcdb8](https://github.com/fluttercommunity/plus_plugins/commit/f2fbcdb813b62dcb76c18b00e51383e6643a93ed)) + +## 10.0.0 + +> Note: This release was retracted due to ([#2251](https://github.com/fluttercommunity/plus_plugins/issues/2251)). + +## 9.1.2 + + - **FIX**(device_info_plus): fix crash on non-standard Digital Product IDs ([#2537](https://github.com/fluttercommunity/plus_plugins/issues/2537)). ([7b318b5c](https://github.com/fluttercommunity/plus_plugins/commit/7b318b5cd8496cf7d31c62314eb9bae17f9ef8d6)) + +## 9.1.1 + + - **FIX**(device_info_plus): Fix deprecation warning on MacOS ([#2377](https://github.com/fluttercommunity/plus_plugins/issues/2377)). ([56a6d0ff](https://github.com/fluttercommunity/plus_plugins/commit/56a6d0ff3752570de89f00876eb7181d662a0465)) + +## 9.1.0 + +> Info: This release is a replacement for release 10.0.0, which was retracted due to issue ([#2251](https://github.com/fluttercommunity/plus_plugins/issues/2251)). As breaking change was reverted the major release was also reverted in favor of this one. + + - **FIX**(device_info_plus): Change Kotlin version from 1.9.10 to 1.7.22 ([#2256](https://github.com/fluttercommunity/plus_plugins/issues/2256)). ([313ec2c3](https://github.com/fluttercommunity/plus_plugins/commit/313ec2c328f34b278f197ee1f2d896f8820ac789)) + - **FIX**(device_info_plus): Revert bump compileSDK to 34 ([#2230](https://github.com/fluttercommunity/plus_plugins/issues/2230)). ([2ba5b054](https://github.com/fluttercommunity/plus_plugins/commit/2ba5b054948f48a9aae72c8a63b39f6536ab678d)) + - **FIX**(device_info_plus): Update exports to avoid web compatibility issues ([#2028](https://github.com/fluttercommunity/plus_plugins/issues/2028)). ([6c216053](https://github.com/fluttercommunity/plus_plugins/commit/6c2160537dc51493adc5bf22cd480a52582845b0)) + - **FIX**(device_info_plus): Regenerate iOS and MacOS example apps ([#1868](https://github.com/fluttercommunity/plus_plugins/issues/1868)). ([6e1111ac](https://github.com/fluttercommunity/plus_plugins/commit/6e1111acff40fef6f77fe2561810d679bafe938c)) + - **FEAT**(device_info_plus): Remove deprecated VALID_ARCHS iOS property ([#2022](https://github.com/fluttercommunity/plus_plugins/issues/2022)). ([13053295](https://github.com/fluttercommunity/plus_plugins/commit/13053295137201b34a6bf52e494ccf77e0321b18)) + - **DOCS**(device_info_plus): Add note about arch returned value on MacOS ([#2220](https://github.com/fluttercommunity/plus_plugins/issues/2220)). ([80409e2a](https://github.com/fluttercommunity/plus_plugins/commit/80409e2ab13a6379b9101034ad453517151a719a)) + - **DOCS**(all): Fix example links on pub.dev ([#1863](https://github.com/fluttercommunity/plus_plugins/issues/1863)). ([d726035a](https://github.com/fluttercommunity/plus_plugins/commit/d726035ad7631d5a1397d0a2e5df23dc7e30a4f7)) + +## 9.0.3 + + - **FIX**(device_info_plus): Regenerate iOS and MacOS example apps ([#1868](https://github.com/fluttercommunity/plus_plugins/issues/1868)). ([6e1111ac](https://github.com/fluttercommunity/plus_plugins/commit/6e1111acff40fef6f77fe2561810d679bafe938c)) + - **DOCS**(all): Fix example links on pub.dev ([#1863](https://github.com/fluttercommunity/plus_plugins/issues/1863)). ([d726035a](https://github.com/fluttercommunity/plus_plugins/commit/d726035ad7631d5a1397d0a2e5df23dc7e30a4f7)) + +## 9.0.2 + + - **DOCS**(device_info_plus): Add links to Android and iOS docs to every field ([#1857](https://github.com/fluttercommunity/plus_plugins/issues/1857)). ([89eb5217](https://github.com/fluttercommunity/plus_plugins/commit/89eb52177c90d5453ba512e73472536fc8a03c9a)) + +## 9.0.1 + + - **FIX**: Add jvm target compatibility to Kotlin plugins ([#1798](https://github.com/fluttercommunity/plus_plugins/issues/1798)). ([1b7dc432](https://github.com/fluttercommunity/plus_plugins/commit/1b7dc432ffb8d0474c9be6339d20b5a2cbcbab3f)) + - **DOCS**(all): Update READMEs ([#1828](https://github.com/fluttercommunity/plus_plugins/issues/1828)). ([57d9c884](https://github.com/fluttercommunity/plus_plugins/commit/57d9c8845edfc81fdbabcef9eb1d1ca450e62e7d)) + - **CHORE**(device_info_plus): Win32 dependency upgrade ([#1805](https://github.com/fluttercommunity/plus_plugins/pull/1805)). ([3f68800](https://github.com/fluttercommunity/plus_plugins/commit/c8f7b6342a7c51eafafae95792775505d2b52ce9)) + +## 9.0.0 + +> Note: This release has breaking changes. + + - **CHORE**(device_info_plus): Update Flutter dependencies, set Flutter >=3.3.0 and Dart to >=2.18.0 <4.0.0 + - **BREAKING** **FIX**(all): Add support of namespace property to support Android Gradle Plugin (AGP) 8 (#1727). Projects with AGP < 4.2 are not supported anymore. It is highly recommended to update at least to AGP 7.0 or newer. + - **BREAKING** **CHORE**(device_info_plus): Bump min Android to 4.4 (API 19) and iOS to 11, update podspec file (#1781). + - **REFACTOR**(device_info_plus): Refactor Windows implementation (#1772). + - **REFACTOR**(device_info_plus): Remove redundant checks for PRODUCT strings with sdk (#1745). + - **REFACTOR**(device_info_plus): Declare proper nullability for iOS properties (#1728). + +## 8.2.2 + + - **FIX**(all): Revert addition of namespace to avoid build fails on old AGPs (#1725). + +## 8.2.1 + + - **FIX**(device_info_plus): Add compatibility with AGP 8 (Android Gradle Plugin) (#1702). + +## 8.2.0 + + - **REFACTOR**(all): Remove all manual dependency_overrides (#1628). + - **FEAT**(device_info_plus): add major, minor and patch versions to macos (#1649). + +## 8.1.0 + + - **FEAT**: Add serialNumber property to AndroidDeviceInfo (#1349). + - **DOCS**: Updates for READMEs and website pages (#1389). + - **DOCS**: Explain how to get serial number on Android (#1390). + - **DOCS**: Add info about iOS 16 changes to device name (#1356). + +## 8.0.0 + +> Note: This release has breaking changes. + + - **DOCS**: Document toMap deprecation (#1292). + - **BREAKING** **FEAT**: refactor of device_info_plus platform implementation (#1293). + +## 7.0.1 + + - **FIX**: Increase min Flutter version to fix dartPluginClass registration (#1275). + +## 7.0.0 + +> Note: This release has breaking changes. + + - **REFACTOR**: Migrate Android part to Kotlin, update Android dependencies (#1245). + - **FIX**: add `@Deprecated` annotation to `toMap` method (#1142). + - **DOCS**: Add info about Android properties availability, update API docs links (#1243). + - **BREAKING** **REFACTOR**: two-package federated architecture (#1228). + +## 6.0.0 + +> Note: This release has breaking changes. + + - **BREAKING** **FEAT**: Add support of Android display metrics (#829). + +## 5.0.5 + + - Update a dependency to the latest release. + +## 5.0.4 + + - **FIX**: fixed wrong dependency version #1175. + +## 5.0.3 + + - **FIX**: fix version dependency. + +## 5.0.2 + + - **CHORE**: Version tagging using melos. + +## 5.0.1 + +- Fixing federated plugin architecture versions. + +## 5.0.0 + +- Re-introduce: Added more information to `WindowsDeviceInfo`. +- device_info_plus_platform_interface to 4.0.0 + +## 4.1.3 + +- Detects iOS simulator device id instead of simulator's underlying architecture. + +## 4.1.2 + +- Redo changes in 4.1.0 +- device_info_plus_platform_interface to 3.0.0 + +## 4.1.1 + +- Revert changes in 4.1.0 + +## 4.1.0 + +- Remove `androidId` (that already got removed from the method channel in 4.0.0, thus always returned null) +- There is a **new, separate [pub.dev package](https://pub.dev/packages/android_id) for getting the correct `androidId`** + +## 4.0.3 + +- Reverted changes in 4.0.2 + +## 4.0.2 + +- Added more information to `WindowsDeviceInfo`. + +## 4.0.1 + +- Update dependencies + +## 4.0.0 + +- **Breaking change** Remove `AndroidId` getter to avoid Google Play policies violations +- Update flutter_lints to 2.0.1 +- Remove explicit `test` dependency to use `flutter_test` from Flutter SDK + +## 3.2.4 + +- Update the description of getAndroidId method + +## 3.2.3 + +- Fix crash on macOS running on Apple M1 + +## 3.2.2 + +- Fix embedding issue in example +- Update Android dependencies in example + +## 3.2.1 + +- iOS: fix `identifierForVendor` (can be `null` in rare circumstances) +- Use automatic plugin registration on Linux and Windows +- Fix warnings when building for macOS + +## 3.2.0 + +- add `deviceInfo` + +## 3.1.1 + +- add toMap to WebBrowserInfo + +## 3.1.0 + +- add System GUID to MacOS + +## 3.0.1 + +- Upgrade Android compile SDK version +- Several code improvements + +## 3.0.0 + +- Remove deprecated method `registerWith` (of Android v1 embedding) + +## 2.2.0 + +- migrate integration_test to flutter sdk + +## 2.1.0 + +- add toMap to models + +## 2.0.1 + +- Android: migrate to mavenCentral + +## 2.0.0 + +- WebBrowserInfo properties are now nullable + +## 1.0.1 + +- Improve documentation + +## 1.0.0 + +- Migrated to null safety +- Update dependencies. + +## 0.7.2 + +- Update dependencies. + +## 0.7.1 + +- Fix macOS support. + +## 0.7.0 + +- Add macOS support via `device_info_plus_macos`. + +## 0.6.0 + +- Rename method channel to avoid conflicts. + +## 0.5.0 + +- Transfer to plus-plugins monorepo + +## 0.4.2+8 + +- Transfer package to Flutter Community under new name `device_info_plus`. + +## 0.4.2+7 + +- Port device_info plugin to use platform interface. + +## 0.4.2+6 + +- Moved everything from device_info to device_info/device_info + +## 0.4.2+5 + +- Update package:e2e reference to use the local version in the flutter/plugins + repository. + +## 0.4.2+4 + +Update lower bound of dart dependency to 2.1.0. + +## 0.4.2+3 + +- Declare API stability and compatibility with `1.0.0` (more details at: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0). + +## 0.4.2+2 + +- Fix CocoaPods podspec lint warnings. + +## 0.4.2+1 + +- Bump the minimum Flutter version to 1.12.13+hotfix.5. +- Remove deprecated API usage warning in AndroidIntentPlugin.java. +- Migrates the Android example to V2 embedding. +- Bumps AGP to 3.6.1. + +## 0.4.2 + +- Add systemFeatures to AndroidDeviceInfo. + +## 0.4.1+5 + +- Make the pedantic dev_dependency explicit. + +## 0.4.1+4 + +- Remove the deprecated `author:` field from pubspec.yaml +- Migrate the plugin to the pubspec platforms manifest. +- Require Flutter SDK 1.10.0 or greater. + +## 0.4.1+3 + +- Fix pedantic errors. Adds some missing documentation and fixes unawaited + futures in the tests. + +## 0.4.1+2 + +- Remove AndroidX warning. + +## 0.4.1+1 + +- Include lifecycle dependency as a compileOnly one on Android to resolve + potential version conflicts with other transitive libraries. + +## 0.4.1 + +- Support the v2 Android embedding. +- Update to AndroidX. +- Migrate to using the new e2e test binding. +- Add a e2e test. + +## 0.4.0+4 + +- Define clang module for iOS. + +## 0.4.0+3 + +- Update and migrate iOS example project. + +## 0.4.0+2 + +- Bump minimum Flutter version to 1.5.0. +- Add missing template type parameter to `invokeMethod` calls. +- Replace invokeMethod with invokeMapMethod wherever necessary. + +## 0.4.0+1 + +- Log a more detailed warning at build time about the previous AndroidX + migration. + +## 0.4.0 + +- **Breaking change**. Migrate from the deprecated original Android Support + Library to AndroidX. This shouldn't result in any functional changes, but it + requires any Android apps using this plugin to [also + migrate](https://developer.android.com/jetpack/androidx/migrate) if they're + using the original support library. + +## 0.3.0 + +- Added ability to get Android ID for Android devices + +## 0.2.1 + +- Updated Gradle tooling to match Android Studio 3.1.2. + +## 0.2.0 + +- **Breaking change**. Set SDK constraints to match the Flutter beta release. + +## 0.1.2 + +- Fixed Dart 2 type errors. + +## 0.1.1 + +- Simplified and upgraded Android project template to Android SDK 27. +- Updated package description. + +## 0.1.0 + +- **Breaking change**. Upgraded to Gradle 4.1 and Android Studio Gradle plugin + 3.0.1. Older Flutter projects need to upgrade their Gradle setup as well in + order to use this version of the plugin. Instructions can be found + [here](https://github.com/flutter/flutter/wiki/Updating-Flutter-projects-to-Gradle-4.1-and-Android-Studio-Gradle-plugin-3.0.1). + +## 0.0.5 + +- Added FLT prefix to iOS types + +## 0.0.4 + +- Fixed Java/Dart communication error with empty lists + +## 0.0.3 + +- Added support for utsname + +## 0.0.2 + +- Fixed broken type comparison +- Added "isPhysicalDevice" field, detecting emulators/simulators + +## 0.0.1 + +- Implements platform-specific device/OS properties diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/build.gradle b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/build.gradle new file mode 100644 index 00000000..79a345a4 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/build.gradle @@ -0,0 +1,52 @@ +group 'dev.fluttercommunity.plus.device_info' +version '1.0-SNAPSHOT' + +buildscript { + ext.kotlin_version = '2.2.0' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:8.12.1' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +rootProject.allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + namespace 'dev.fluttercommunity.plus.device_info' + compileSdk = flutter.compileSdkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = 17 + } + + defaultConfig { + minSdk 19 + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + lintOptions { + disable 'InvalidPackage', 'MissingPermission' + } + + dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/gradle.properties b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/gradle.properties new file mode 100644 index 00000000..8bd86f68 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/settings.gradle b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/settings.gradle new file mode 100644 index 00000000..0e75718c --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'device_info' diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/src/main/AndroidManifest.xml b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000..412ea27f --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/src/main/kotlin/dev/fluttercommunity/plus/device_info/DeviceInfoPlusPlugin.kt b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/src/main/kotlin/dev/fluttercommunity/plus/device_info/DeviceInfoPlusPlugin.kt new file mode 100644 index 00000000..3ba8c921 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/src/main/kotlin/dev/fluttercommunity/plus/device_info/DeviceInfoPlusPlugin.kt @@ -0,0 +1,32 @@ +package dev.fluttercommunity.plus.device_info + +import android.app.ActivityManager +import android.content.Context +import android.content.pm.PackageManager +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.MethodChannel + +/** DeviceInfoPlusPlugin */ +class DeviceInfoPlusPlugin : FlutterPlugin { + + private lateinit var methodChannel: MethodChannel + + override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) { + setupMethodChannel(binding.binaryMessenger, binding.applicationContext) + } + + override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { + methodChannel.setMethodCallHandler(null) + } + + private fun setupMethodChannel(messenger: BinaryMessenger, context: Context) { + methodChannel = MethodChannel(messenger, "dev.fluttercommunity.plus/device_info") + val packageManager: PackageManager = context.packageManager + val activityManager: ActivityManager = + context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + val contentResolver = context.contentResolver + val handler = MethodCallHandlerImpl(packageManager, activityManager, contentResolver) + methodChannel.setMethodCallHandler(handler) + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/src/main/kotlin/dev/fluttercommunity/plus/device_info/MethodCallHandlerImpl.kt b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/src/main/kotlin/dev/fluttercommunity/plus/device_info/MethodCallHandlerImpl.kt new file mode 100644 index 00000000..2d82b027 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/android/src/main/kotlin/dev/fluttercommunity/plus/device_info/MethodCallHandlerImpl.kt @@ -0,0 +1,114 @@ +package dev.fluttercommunity.plus.device_info + +import android.app.ActivityManager +import android.content.ContentResolver +import android.content.pm.FeatureInfo +import android.content.pm.PackageManager +import android.os.Build +import android.provider.Settings +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel +import io.flutter.plugin.common.MethodChannel.MethodCallHandler +import kotlin.collections.HashMap +import android.os.StatFs +import android.os.Environment + +/** + * The implementation of [MethodChannel.MethodCallHandler] for the plugin. Responsible for + * receiving method calls from method channel. + */ +internal class MethodCallHandlerImpl( + private val packageManager: PackageManager, + private val activityManager: ActivityManager, + private val contentResolver: ContentResolver, +) : MethodCallHandler { + + override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { + if (call.method.equals("getDeviceInfo")) { + val build: MutableMap = HashMap() + + build["board"] = Build.BOARD + build["bootloader"] = Build.BOOTLOADER + build["brand"] = Build.BRAND + build["device"] = Build.DEVICE + build["display"] = Build.DISPLAY + build["fingerprint"] = Build.FINGERPRINT + build["hardware"] = Build.HARDWARE + build["host"] = Build.HOST + build["id"] = Build.ID + build["manufacturer"] = Build.MANUFACTURER + build["model"] = Build.MODEL + build["product"] = Build.PRODUCT + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { + build["name"] = Settings.Global.getString(contentResolver, Settings.Global.DEVICE_NAME) ?: "" + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + build["supported32BitAbis"] = listOf(*Build.SUPPORTED_32_BIT_ABIS) + build["supported64BitAbis"] = listOf(*Build.SUPPORTED_64_BIT_ABIS) + build["supportedAbis"] = listOf(*Build.SUPPORTED_ABIS) + } else { + build["supported32BitAbis"] = emptyList() + build["supported64BitAbis"] = emptyList() + build["supportedAbis"] = emptyList() + } + + build["tags"] = Build.TAGS + build["type"] = Build.TYPE + build["isPhysicalDevice"] = !isEmulator + build["systemFeatures"] = getSystemFeatures() + + val statFs = StatFs(Environment.getDataDirectory().getPath()) + build["freeDiskSize"] = statFs.getFreeBytes() + build["totalDiskSize"] = statFs.getTotalBytes() + + val version: MutableMap = HashMap() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + version["baseOS"] = Build.VERSION.BASE_OS + version["previewSdkInt"] = Build.VERSION.PREVIEW_SDK_INT + version["securityPatch"] = Build.VERSION.SECURITY_PATCH + } + version["codename"] = Build.VERSION.CODENAME + version["incremental"] = Build.VERSION.INCREMENTAL + version["release"] = Build.VERSION.RELEASE + version["sdkInt"] = Build.VERSION.SDK_INT + build["version"] = version + + val memoryInfo: ActivityManager.MemoryInfo = ActivityManager.MemoryInfo() + activityManager.getMemoryInfo(memoryInfo) + build["isLowRamDevice"] = memoryInfo.lowMemory + build["physicalRamSize"] = memoryInfo.totalMem / 1048576L // Mb + build["availableRamSize"] = memoryInfo.availMem / 1048576L // Mb + result.success(build) + } else { + result.notImplemented() + } + } + + private fun getSystemFeatures(): List { + val featureInfos: Array = packageManager.systemAvailableFeatures + return featureInfos + .filterNot { featureInfo -> featureInfo.name == null } + .map { featureInfo -> featureInfo.name } + } + + /** + * A simple emulator-detection based on the flutter tools detection logic and a couple of legacy + * detection systems + */ + private val isEmulator: Boolean + get() = ((Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) + || Build.FINGERPRINT.startsWith("generic") + || Build.FINGERPRINT.startsWith("unknown") + || Build.HARDWARE.contains("goldfish") + || Build.HARDWARE.contains("ranchu") + || Build.MODEL.contains("google_sdk") + || Build.MODEL.contains("Emulator") + || Build.MODEL.contains("Android SDK built for x86") + || Build.MANUFACTURER.contains("Genymotion") + || Build.PRODUCT.contains("sdk") + || Build.PRODUCT.contains("vbox86p") + || Build.PRODUCT.contains("emulator") + || Build.PRODUCT.contains("simulator")) +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/build.gradle b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/build.gradle new file mode 100644 index 00000000..c6e51e66 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/build.gradle @@ -0,0 +1,65 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +android { + namespace 'io.flutter.plugins.deviceinfoexample.example' + compileSdk = flutter.compileSdkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = 17 + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + applicationId "io.flutter.plugins.deviceinfoexample.example" + minSdk flutter.minSdkVersion + targetSdk flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/debug/AndroidManifest.xml b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..175e81dc --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/AndroidManifest.xml b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..d75557c5 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/kotlin/io/flutter/plugins/deviceinfoexample/example/MainActivity.kt b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/kotlin/io/flutter/plugins/deviceinfoexample/example/MainActivity.kt new file mode 100644 index 00000000..e2bd9925 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/kotlin/io/flutter/plugins/deviceinfoexample/example/MainActivity.kt @@ -0,0 +1,21 @@ +package io.flutter.plugins.deviceinfoexample.example + +import android.os.Build +import android.os.Bundle +import android.os.StrictMode +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + // Ensures correct use of Activity Context to obtain the WindowManager + StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder() + .detectIncorrectContextUse() + .penaltyLog() + .penaltyDeath() + .build()) + } + super.onCreate(savedInstanceState) + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/drawable/launch_background.xml b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..db77bb4b Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..17987b79 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..09d43914 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..d5f1c8d3 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..4d6372ee Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/values/styles.xml b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..1f83a33f --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/profile/AndroidManifest.xml b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..175e81dc --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/build.gradle b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/build.gradle new file mode 100644 index 00000000..bc157bd1 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/build.gradle @@ -0,0 +1,18 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/gradle.properties b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/gradle.properties new file mode 100644 index 00000000..d9cf55df --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/gradle.properties @@ -0,0 +1,2 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/gradle/wrapper/gradle-wrapper.properties b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..f3dd2fa1 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Oct 05 15:15:38 CEST 2021 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/settings.gradle b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/settings.gradle new file mode 100644 index 00000000..f1c2904d --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/android/settings.gradle @@ -0,0 +1,25 @@ +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "8.12.1" apply false + id "org.jetbrains.kotlin.android" version "2.2.0" apply false +} + +include ":app" diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/integration_test/device_info_plus_test.dart b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/integration_test/device_info_plus_test.dart new file mode 100644 index 00000000..be6d7531 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/integration_test/device_info_plus_test.dart @@ -0,0 +1,186 @@ +// Copyright 2019, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + late IosDeviceInfo iosInfo; + late AndroidDeviceInfo androidInfo; + late WebBrowserInfo webBrowserInfo; + late WindowsDeviceInfo windowsInfo; + late LinuxDeviceInfo linuxInfo; + late MacOsDeviceInfo macosInfo; + late BaseDeviceInfo deviceInfo; + + setUpAll(() async { + final deviceInfoPlugin = DeviceInfoPlugin(); + if (kIsWeb) { + webBrowserInfo = await deviceInfoPlugin.webBrowserInfo; + } else { + if (Platform.isIOS) { + iosInfo = await deviceInfoPlugin.iosInfo; + } else if (Platform.isAndroid) { + androidInfo = await deviceInfoPlugin.androidInfo; + } else if (Platform.isWindows) { + windowsInfo = await deviceInfoPlugin.windowsInfo; + } else if (Platform.isLinux) { + linuxInfo = await deviceInfoPlugin.linuxInfo; + } else if (Platform.isMacOS) { + macosInfo = await deviceInfoPlugin.macOsInfo; + } + } + + deviceInfo = await deviceInfoPlugin.deviceInfo; + }); + + testWidgets('Can get non-null device model', (WidgetTester tester) async { + if (kIsWeb) { + expect(webBrowserInfo.userAgent, isNotNull); + expect(deviceInfo, same(webBrowserInfo)); + } else { + if (Platform.isIOS) { + expect(iosInfo.model, isNotNull); + expect(deviceInfo, same(iosInfo)); + } else if (Platform.isAndroid) { + expect(androidInfo.model, isNotNull); + expect(deviceInfo, same(androidInfo)); + } else if (Platform.isWindows) { + expect(windowsInfo.computerName, isNotNull); + expect(deviceInfo, same(windowsInfo)); + } else if (Platform.isLinux) { + expect(linuxInfo.name, isNotNull); + expect(deviceInfo, same(linuxInfo)); + } else if (Platform.isMacOS) { + expect(macosInfo.computerName, isNotNull); + expect(deviceInfo, same(macosInfo)); + } + } + }); + + testWidgets('Can get non-null iOS utsname fields', ( + WidgetTester tester, + ) async { + expect(iosInfo.utsname.machine, isNotNull); + expect(iosInfo.utsname.nodename, isNotNull); + expect(iosInfo.utsname.release, isNotNull); + expect(iosInfo.utsname.sysname, isNotNull); + expect(iosInfo.utsname.version, isNotNull); + }, skip: !Platform.isIOS); + + testWidgets('Check all android info values are available', ( + WidgetTester tester, + ) async { + if (androidInfo.version.sdkInt >= 23) { + expect(androidInfo.version.baseOS, isNotNull); + expect(androidInfo.version.previewSdkInt, isNotNull); + expect(androidInfo.version.securityPatch, isNotNull); + } + + expect(androidInfo.version.codename, isNotNull); + expect(androidInfo.version.incremental, isNotNull); + expect(androidInfo.version.release, isNotNull); + expect(androidInfo.version.sdkInt, isNotNull); + expect(androidInfo.board, isNotNull); + expect(androidInfo.bootloader, isNotNull); + expect(androidInfo.brand, isNotNull); + expect(androidInfo.device, isNotNull); + expect(androidInfo.display, isNotNull); + expect(androidInfo.fingerprint, isNotNull); + expect(androidInfo.hardware, isNotNull); + + expect(androidInfo.host, isNotNull); + expect(androidInfo.id, isNotNull); + expect(androidInfo.manufacturer, isNotNull); + expect(androidInfo.model, isNotNull); + expect(androidInfo.product, isNotNull); + expect(androidInfo.name, isNotNull); + + expect(androidInfo.supported32BitAbis, isNotNull); + expect(androidInfo.supported64BitAbis, isNotNull); + expect(androidInfo.supportedAbis, isNotNull); + + expect(androidInfo.tags, isNotNull); + expect(androidInfo.type, isNotNull); + expect(androidInfo.isPhysicalDevice, isNotNull); + expect(androidInfo.systemFeatures, isNotNull); + }, skip: !Platform.isAndroid); + + testWidgets('Check all macos info values are available', (( + WidgetTester tester, + ) async { + expect(macosInfo.computerName, isNotNull); + expect(macosInfo.hostName, isNotNull); + expect(macosInfo.arch, isNotNull); + expect(macosInfo.model, isNotNull); + expect(macosInfo.modelName, isNotNull); + expect(macosInfo.kernelVersion, isNotNull); + expect(macosInfo.osRelease, isNotNull); + expect(macosInfo.activeCPUs, isNotNull); + expect(macosInfo.memorySize, isNotNull); + expect(macosInfo.cpuFrequency, isNotNull); + expect(macosInfo.systemGUID, isNotNull); + }), skip: !Platform.isMacOS); + + testWidgets('Check all Linux info values are available', (( + WidgetTester tester, + ) async { + expect(linuxInfo.name, isNotNull); + expect(linuxInfo.version, isNotNull); + expect(linuxInfo.id, isNotNull); + expect(linuxInfo.idLike, isNotNull); + expect(linuxInfo.versionCodename, isNotNull); + expect(linuxInfo.versionId, isNotNull); + expect(linuxInfo.prettyName, isNotNull); + expect(linuxInfo.buildId, isNull); + expect(linuxInfo.variant, isNull); + expect(linuxInfo.variantId, isNull); + }), skip: !Platform.isLinux); + + testWidgets('Check all Windows info values are available', (( + WidgetTester tester, + ) async { + expect(windowsInfo.numberOfCores, isPositive); + expect(windowsInfo.computerName, isNotEmpty); + expect(windowsInfo.systemMemoryInMegabytes, isPositive); + expect(windowsInfo.userName, isNotEmpty); + expect(windowsInfo.majorVersion, equals(10)); + expect(windowsInfo.minorVersion, equals(0)); + expect(windowsInfo.buildNumber, greaterThan(10240)); + expect(windowsInfo.platformId, equals(2)); + expect(windowsInfo.reserved, isZero); + expect(windowsInfo.buildLab, isNotEmpty); + expect( + windowsInfo.buildLab, + startsWith(windowsInfo.buildNumber.toString()), + ); + expect(windowsInfo.buildLabEx, isNotEmpty); + expect( + windowsInfo.buildLab, + startsWith(windowsInfo.buildNumber.toString()), + ); + expect(windowsInfo.digitalProductId, isNotEmpty); + expect(windowsInfo.editionId, isNotEmpty); + expect(windowsInfo.productId, isNotEmpty); + expect( + RegExp( + r'^([A-Z0-9]{5}-){4}[A-Z0-9]{5}$', + ).hasMatch(windowsInfo.productId) || + RegExp( + r'^([A-Z0-9]{5}-){3}[A-Z0-9]{5}$', + ).hasMatch(windowsInfo.productId), + isTrue, + ); + expect(windowsInfo.productName, isNotEmpty); + expect(windowsInfo.productName, startsWith('Windows')); + expect(windowsInfo.releaseId, isNotEmpty); + expect(windowsInfo.deviceId, isNotEmpty); + }), skip: !Platform.isWindows); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Flutter/AppFrameworkInfo.plist b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..8c6e5614 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Flutter/Debug.xcconfig b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..ec97fc6f --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Flutter/Release.xcconfig b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..c4855bfe --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcodeproj/project.pbxproj b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..075d8eec --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,723 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 429829504B428B91CD34394A /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E34A4006F430DB1C5A018A69 /* Pods_Runner.framework */; }; + 5DA2260ADE5F76F3FFB815A0 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CDBB1B1CAFCC61F3647887B /* Pods_RunnerTests.framework */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0CDBB1B1CAFCC61F3647887B /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 6FDE560C1C66BB7D507C271F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 70B46233CBC827D9357CAED6 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B3E39AFFADC3FF84A14CEAD9 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + B5226E28C7B6DFA3F85A5F86 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + CC560B6DE1FF1FA91F20AF89 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + E34A4006F430DB1C5A018A69 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F7BF1F60B00C1E3390715BB3 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 479820A9DCB23F89315408D4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5DA2260ADE5F76F3FFB815A0 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 429829504B428B91CD34394A /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 2A76172809353E74F0878C8F /* Frameworks */ = { + isa = PBXGroup; + children = ( + E34A4006F430DB1C5A018A69 /* Pods_Runner.framework */, + 0CDBB1B1CAFCC61F3647887B /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + EE25C9049E007CD6D24A97DF /* Pods */, + 2A76172809353E74F0878C8F /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + EE25C9049E007CD6D24A97DF /* Pods */ = { + isa = PBXGroup; + children = ( + 6FDE560C1C66BB7D507C271F /* Pods-Runner.debug.xcconfig */, + 70B46233CBC827D9357CAED6 /* Pods-Runner.release.xcconfig */, + B5226E28C7B6DFA3F85A5F86 /* Pods-Runner.profile.xcconfig */, + B3E39AFFADC3FF84A14CEAD9 /* Pods-RunnerTests.debug.xcconfig */, + CC560B6DE1FF1FA91F20AF89 /* Pods-RunnerTests.release.xcconfig */, + F7BF1F60B00C1E3390715BB3 /* Pods-RunnerTests.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + AC296610EEC611E8563F8C04 /* [CP] Check Pods Manifest.lock */, + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + 479820A9DCB23F89315408D4 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + F83E525764739090E301A316 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 4FD9CA2815573411DDA641D3 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 4FD9CA2815573411DDA641D3 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + AC296610EEC611E8563F8C04 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + F83E525764739090E301A316 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.exampleDeviceInfo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B3E39AFFADC3FF84A14CEAD9 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.exampleDeviceInfo.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = CC560B6DE1FF1FA91F20AF89 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.exampleDeviceInfo.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F7BF1F60B00C1E3390715BB3 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.exampleDeviceInfo.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.exampleDeviceInfo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.exampleDeviceInfo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..8e3ca5df --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/AppDelegate.swift b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/AppDelegate.swift new file mode 100644 index 00000000..b6363034 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@main +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..dc9ada47 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 00000000..7353c41e Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 00000000..797d452e Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 00000000..6ed2d933 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 00000000..4cd7b009 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 00000000..fe730945 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 00000000..321773cd Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 00000000..797d452e Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 00000000..502f463a Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 00000000..0ec30343 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 00000000..0ec30343 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 00000000..e9f5fea2 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 00000000..84ac32ae Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 00000000..8953cba0 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 00000000..0467bf12 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 00000000..0bedcf2f --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f2e259c7 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Base.lproj/Main.storyboard b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Info.plist b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Info.plist new file mode 100644 index 00000000..c30f9332 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Info.plist @@ -0,0 +1,51 @@ + + + + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Device Info Plus + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + device_info_plus_example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Runner-Bridging-Header.h b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 00000000..308a2a56 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/RunnerTests/RunnerTests.swift b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/lib/main.dart b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/lib/main.dart new file mode 100644 index 00000000..5a70d40d --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/lib/main.dart @@ -0,0 +1,279 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'dart:async'; +import 'dart:developer' as developer; + +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +void main() { + runZonedGuarded( + () { + runApp(const MyApp()); + }, + (dynamic error, dynamic stack) { + developer.log("Something went wrong!", error: error, stackTrace: stack); + }, + ); +} + +class MyApp extends StatefulWidget { + const MyApp({super.key}); + + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + static final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin(); + Map _deviceData = {}; + + @override + void initState() { + super.initState(); + initPlatformState(); + } + + Future initPlatformState() async { + var deviceData = {}; + + try { + if (kIsWeb) { + deviceData = _readWebBrowserInfo(await deviceInfoPlugin.webBrowserInfo); + } else { + deviceData = switch (defaultTargetPlatform) { + TargetPlatform.android => _readAndroidBuildData( + await deviceInfoPlugin.androidInfo, + ), + TargetPlatform.iOS => _readIosDeviceInfo( + await deviceInfoPlugin.iosInfo, + ), + TargetPlatform.linux => _readLinuxDeviceInfo( + await deviceInfoPlugin.linuxInfo, + ), + TargetPlatform.windows => _readWindowsDeviceInfo( + await deviceInfoPlugin.windowsInfo, + ), + TargetPlatform.macOS => _readMacOsDeviceInfo( + await deviceInfoPlugin.macOsInfo, + ), + TargetPlatform.fuchsia => { + 'Error:': 'Fuchsia platform isn\'t supported', + }, + }; + } + } on PlatformException { + deviceData = { + 'Error:': 'Failed to get platform version.', + }; + } + + if (!mounted) return; + + setState(() { + _deviceData = deviceData; + }); + } + + Map _readAndroidBuildData(AndroidDeviceInfo build) { + return { + 'version.securityPatch': build.version.securityPatch, + 'version.sdkInt': build.version.sdkInt, + 'version.release': build.version.release, + 'version.previewSdkInt': build.version.previewSdkInt, + 'version.incremental': build.version.incremental, + 'version.codename': build.version.codename, + 'version.baseOS': build.version.baseOS, + 'board': build.board, + 'bootloader': build.bootloader, + 'brand': build.brand, + 'device': build.device, + 'display': build.display, + 'fingerprint': build.fingerprint, + 'hardware': build.hardware, + 'host': build.host, + 'id': build.id, + 'manufacturer': build.manufacturer, + 'model': build.model, + 'product': build.product, + 'name': build.name, + 'supported32BitAbis': build.supported32BitAbis, + 'supported64BitAbis': build.supported64BitAbis, + 'supportedAbis': build.supportedAbis, + 'tags': build.tags, + 'type': build.type, + 'isPhysicalDevice': build.isPhysicalDevice, + 'freeDiskSize': build.freeDiskSize, + 'totalDiskSize': build.totalDiskSize, + 'systemFeatures': build.systemFeatures, + 'isLowRamDevice': build.isLowRamDevice, + 'physicalRamSize': build.physicalRamSize, + 'availableRamSize': build.availableRamSize, + }; + } + + Map _readIosDeviceInfo(IosDeviceInfo data) { + return { + 'name': data.name, + 'systemName': data.systemName, + 'systemVersion': data.systemVersion, + 'model': data.model, + 'modelName': data.modelName, + 'localizedModel': data.localizedModel, + 'identifierForVendor': data.identifierForVendor, + 'isPhysicalDevice': data.isPhysicalDevice, + 'isiOSAppOnMac': data.isiOSAppOnMac, + 'freeDiskSize': data.freeDiskSize, + 'totalDiskSize': data.totalDiskSize, + 'physicalRamSize': data.physicalRamSize, + 'availableRamSize': data.availableRamSize, + 'utsname.sysname:': data.utsname.sysname, + 'utsname.nodename:': data.utsname.nodename, + 'utsname.release:': data.utsname.release, + 'utsname.version:': data.utsname.version, + 'utsname.machine:': data.utsname.machine, + }; + } + + Map _readLinuxDeviceInfo(LinuxDeviceInfo data) { + return { + 'name': data.name, + 'version': data.version, + 'id': data.id, + 'idLike': data.idLike, + 'versionCodename': data.versionCodename, + 'versionId': data.versionId, + 'prettyName': data.prettyName, + 'buildId': data.buildId, + 'variant': data.variant, + 'variantId': data.variantId, + 'machineId': data.machineId, + }; + } + + Map _readWebBrowserInfo(WebBrowserInfo data) { + return { + 'browserName': data.browserName.name, + 'appCodeName': data.appCodeName, + 'appName': data.appName, + 'appVersion': data.appVersion, + 'deviceMemory': data.deviceMemory, + 'language': data.language, + 'languages': data.languages, + 'platform': data.platform, + 'product': data.product, + 'productSub': data.productSub, + 'userAgent': data.userAgent, + 'vendor': data.vendor, + 'vendorSub': data.vendorSub, + 'hardwareConcurrency': data.hardwareConcurrency, + 'maxTouchPoints': data.maxTouchPoints, + }; + } + + Map _readMacOsDeviceInfo(MacOsDeviceInfo data) { + return { + 'computerName': data.computerName, + 'hostName': data.hostName, + 'arch': data.arch, + 'model': data.model, + 'modelName': data.modelName, + 'kernelVersion': data.kernelVersion, + 'majorVersion': data.majorVersion, + 'minorVersion': data.minorVersion, + 'patchVersion': data.patchVersion, + 'osRelease': data.osRelease, + 'activeCPUs': data.activeCPUs, + 'memorySize': data.memorySize, + 'cpuFrequency': data.cpuFrequency, + 'systemGUID': data.systemGUID, + }; + } + + Map _readWindowsDeviceInfo(WindowsDeviceInfo data) { + return { + 'numberOfCores': data.numberOfCores, + 'computerName': data.computerName, + 'systemMemoryInMegabytes': data.systemMemoryInMegabytes, + 'userName': data.userName, + 'majorVersion': data.majorVersion, + 'minorVersion': data.minorVersion, + 'buildNumber': data.buildNumber, + 'platformId': data.platformId, + 'csdVersion': data.csdVersion, + 'servicePackMajor': data.servicePackMajor, + 'servicePackMinor': data.servicePackMinor, + 'suitMask': data.suitMask, + 'productType': data.productType, + 'reserved': data.reserved, + 'buildLab': data.buildLab, + 'buildLabEx': data.buildLabEx, + 'digitalProductId': data.digitalProductId, + 'displayVersion': data.displayVersion, + 'editionId': data.editionId, + 'installDate': data.installDate, + 'productId': data.productId, + 'productName': data.productName, + 'registeredOwner': data.registeredOwner, + 'releaseId': data.releaseId, + 'deviceId': data.deviceId, + }; + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + theme: ThemeData( + useMaterial3: true, + colorSchemeSeed: const Color(0x9f4376f8), + ), + home: Scaffold( + appBar: AppBar(title: Text(_getAppBarTitle()), elevation: 4), + body: ListView( + children: + _deviceData.keys.map((String property) { + return Row( + children: [ + Container( + padding: const EdgeInsets.all(10), + child: Text( + property, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + Expanded( + child: Container( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Text( + '${_deviceData[property]}', + maxLines: 10, + overflow: TextOverflow.ellipsis, + ), + ), + ), + ], + ); + }).toList(), + ), + ), + ); + } + + String _getAppBarTitle() => + kIsWeb + ? 'Web Browser info' + : switch (defaultTargetPlatform) { + TargetPlatform.android => 'Android Device Info', + TargetPlatform.iOS => 'iOS Device Info', + TargetPlatform.linux => 'Linux Device Info', + TargetPlatform.windows => 'Windows Device Info', + TargetPlatform.macOS => 'MacOS Device Info', + TargetPlatform.fuchsia => 'Fuchsia Device Info', + }; +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/linux/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/linux/CMakeLists.txt new file mode 100644 index 00000000..fe30a3e6 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/linux/CMakeLists.txt @@ -0,0 +1,106 @@ +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +set(BINARY_NAME "example") +set(APPLICATION_ID "io.flutter.plugins.deviceinfoexample.example") + +cmake_policy(SET CMP0063 NEW) + +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Application build +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) +apply_standard_settings(${BINARY_NAME}) +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +add_dependencies(${BINARY_NAME} flutter_assemble) +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/linux/flutter/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..5b465c7e --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/linux/flutter/CMakeLists.txt @@ -0,0 +1,89 @@ +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) +pkg_check_modules(BLKID REQUIRED IMPORTED_TARGET blkid) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO + PkgConfig::BLKID +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/linux/main.cc b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/linux/main.cc new file mode 100644 index 00000000..8bc15615 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/linux/main.cc @@ -0,0 +1,11 @@ +#include "my_application.h" + +int main(int argc, char **argv) { + // Only X11 is currently supported. + // Wayland support is being developed: + // https://github.com/flutter/flutter/issues/57932. + gdk_set_allowed_backends("x11"); + + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/linux/my_application.cc b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/linux/my_application.cc new file mode 100644 index 00000000..cef2f771 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/linux/my_application.cc @@ -0,0 +1,45 @@ +#include "my_application.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication *application) { + GtkWindow *window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + + FlView *view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +static void my_application_class_init(MyApplicationClass *klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; +} + +static void my_application_init(MyApplication *self) {} + +MyApplication *my_application_new() { + return MY_APPLICATION(g_object_new( + my_application_get_type(), "application-id", APPLICATION_ID, nullptr)); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/linux/my_application.h b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/linux/my_application.h new file mode 100644 index 00000000..3258a73c --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication *my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Flutter/Flutter-Debug.xcconfig b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Flutter/Flutter-Release.xcconfig b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner.xcodeproj/project.pbxproj b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..17738f85 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,791 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 1330411FFFFCBD68C52506B9 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F374CDA27EFCEFF13CF00643 /* Pods_Runner.framework */; }; + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + B32C194861AFDC5B38D41D89 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F061CD8A37C585748E94D972 /* Pods_RunnerTests.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 279B31026D7637D54DF99D75 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* example_device_info.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example_device_info.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 7D5FF3AEF35298EDF0C1201D /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + D768A5BD5BCBEE43226A64A7 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + D94DF7FF96C592E0D5C3E009 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + E07B0AE1E178661F8653244B /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + E92B0E6DF286F1A21B388CA1 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + F061CD8A37C585748E94D972 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F374CDA27EFCEFF13CF00643 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B32C194861AFDC5B38D41D89 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1330411FFFFCBD68C52506B9 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + C28D557964D09D46EC4A0164 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* example_device_info.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + C28D557964D09D46EC4A0164 /* Pods */ = { + isa = PBXGroup; + children = ( + E07B0AE1E178661F8653244B /* Pods-Runner.debug.xcconfig */, + 7D5FF3AEF35298EDF0C1201D /* Pods-Runner.release.xcconfig */, + D768A5BD5BCBEE43226A64A7 /* Pods-Runner.profile.xcconfig */, + D94DF7FF96C592E0D5C3E009 /* Pods-RunnerTests.debug.xcconfig */, + E92B0E6DF286F1A21B388CA1 /* Pods-RunnerTests.release.xcconfig */, + 279B31026D7637D54DF99D75 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + F374CDA27EFCEFF13CF00643 /* Pods_Runner.framework */, + F061CD8A37C585748E94D972 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 55412E34F2958028872E9D98 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 88B27E32653C92A6BA8EB23C /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 5BEC5C74096CA740BAE5D11D /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* example_device_info.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 55412E34F2958028872E9D98 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 5BEC5C74096CA740BAE5D11D /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 88B27E32653C92A6BA8EB23C /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D94DF7FF96C592E0D5C3E009 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.exampleDeviceInfo.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example_device_info.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example_device_info"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E92B0E6DF286F1A21B388CA1 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.exampleDeviceInfo.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example_device_info.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example_device_info"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 279B31026D7637D54DF99D75 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.exampleDeviceInfo.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example_device_info.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example_device_info"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..7bb1c7df --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/AppDelegate.swift b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..8e02df28 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..82b6f9d9 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..13b35eba Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..0a3f5fa4 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bdb57226 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..f083318e Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..326c0e72 Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..2f1632cf Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Base.lproj/MainMenu.xib b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..80e867a4 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Configs/AppInfo.xcconfig b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..af912343 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = device_info_plus_example + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.deviceinfoexample.example + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2023 io.flutter.plugins.deviceinfoexample. All rights reserved. diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Configs/Debug.xcconfig b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Configs/Release.xcconfig b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Configs/Warnings.xcconfig b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/DebugProfile.entitlements b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Info.plist b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/MainFlutterWindow.swift b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Release.entitlements b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/RunnerTests/RunnerTests.swift b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..5418c9f5 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import FlutterMacOS +import Cocoa +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/pubspec.yaml b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/pubspec.yaml new file mode 100644 index 00000000..a3d73752 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/pubspec.yaml @@ -0,0 +1,25 @@ +name: device_info_plus_example +description: Demonstrates how to use the device_info_plus plugin. + +dependencies: + flutter: + sdk: flutter + device_info_plus: ^12.3.0 + +dev_dependencies: + flutter_driver: + sdk: flutter + flutter_test: + sdk: flutter + integration_test: + sdk: flutter + flutter_lints: ">=4.0.0 <6.0.0" + +flutter: + uses-material-design: true + +environment: + sdk: '>=3.7.0 <4.0.0' + flutter: '>=3.29.0' + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/web/favicon.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/web/favicon.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/web/icons/Icon-192.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/web/icons/Icon-192.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/web/icons/Icon-512.png b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/web/icons/Icon-512.png differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/web/index.html b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/web/index.html new file mode 100644 index 00000000..99eacb28 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/web/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + example + + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/web/manifest.json b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/web/manifest.json new file mode 100644 index 00000000..8c012917 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/web/manifest.json @@ -0,0 +1,23 @@ +{ + "name": "example", + "short_name": "example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/CMakeLists.txt new file mode 100644 index 00000000..abf90408 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/CMakeLists.txt @@ -0,0 +1,95 @@ +cmake_minimum_required(VERSION 3.15) +project(example LANGUAGES CXX) + +set(BINARY_NAME "example") + +cmake_policy(SET CMP0063 NEW) + +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() + +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build +add_subdirectory("runner") + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/flutter/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..b02c5485 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/flutter/CMakeLists.txt @@ -0,0 +1,103 @@ +cmake_minimum_required(VERSION 3.15) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..977e38b5 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.15) +project(runner LANGUAGES CXX) + +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "run_loop.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) +apply_standard_settings(${BINARY_NAME}) +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/Runner.rc b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/Runner.rc new file mode 100644 index 00000000..13f98c0a --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#ifdef FLUTTER_BUILD_NUMBER +#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER +#else +#define VERSION_AS_NUMBER 1,0,0 +#endif + +#ifdef FLUTTER_BUILD_NAME +#define VERSION_AS_STRING #FLUTTER_BUILD_NAME +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "io.flutter.plugins.deviceinfoexample" "\0" + VALUE "FileDescription", "A new Flutter project." "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "example" "\0" + VALUE "LegalCopyright", "Copyright (C) 2021 io.flutter.plugins.deviceinfoexample. All rights reserved." "\0" + VALUE "OriginalFilename", "example.exe" "\0" + VALUE "ProductName", "example" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/flutter_window.cpp b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..0f0105d9 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/flutter_window.cpp @@ -0,0 +1,64 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(RunLoop *run_loop, + const flutter::DartProject &project) + : run_loop_(run_loop), project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + run_loop_->RegisterFlutterInstance(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + run_loop_->UnregisterFlutterInstance(flutter_controller_->engine()); + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opporutunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/flutter_window.h b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/flutter_window.h new file mode 100644 index 00000000..69234d4f --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/flutter_window.h @@ -0,0 +1,39 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "run_loop.h" +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { +public: + // Creates a new FlutterWindow driven by the |run_loop|, hosting a + // Flutter view running |project|. + explicit FlutterWindow(RunLoop *run_loop, + const flutter::DartProject &project); + virtual ~FlutterWindow(); + +protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + +private: + // The run loop driving events for this window. + RunLoop *run_loop_; + + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/main.cpp b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/main.cpp new file mode 100644 index 00000000..09895686 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/main.cpp @@ -0,0 +1,41 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "run_loop.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + RunLoop run_loop; + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(&run_loop, project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.CreateAndShow(L"example", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + run_loop.Run(); + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/resource.h b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/resource.h new file mode 100644 index 00000000..d5d958dc --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/resources/app_icon.ico b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/resources/app_icon.ico differ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/run_loop.cpp b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/run_loop.cpp new file mode 100644 index 00000000..31b89f62 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/run_loop.cpp @@ -0,0 +1,66 @@ +#include "run_loop.h" + +#include + +#include + +RunLoop::RunLoop() {} + +RunLoop::~RunLoop() {} + +void RunLoop::Run() { + bool keep_running = true; + TimePoint next_flutter_event_time = TimePoint::clock::now(); + while (keep_running) { + std::chrono::nanoseconds wait_duration = + std::max(std::chrono::nanoseconds(0), + next_flutter_event_time - TimePoint::clock::now()); + ::MsgWaitForMultipleObjects( + 0, nullptr, FALSE, static_cast(wait_duration.count() / 1000), + QS_ALLINPUT); + bool processed_events = false; + MSG message; + // All pending Windows messages must be processed; MsgWaitForMultipleObjects + // won't return again for items left in the queue after PeekMessage. + while (::PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) { + processed_events = true; + if (message.message == WM_QUIT) { + keep_running = false; + break; + } + ::TranslateMessage(&message); + ::DispatchMessage(&message); + // Allow Flutter to process messages each time a Windows message is + // processed, to prevent starvation. + next_flutter_event_time = + std::min(next_flutter_event_time, ProcessFlutterMessages()); + } + // If the PeekMessage loop didn't run, process Flutter messages. + if (!processed_events) { + next_flutter_event_time = + std::min(next_flutter_event_time, ProcessFlutterMessages()); + } + } +} + +void RunLoop::RegisterFlutterInstance( + flutter::FlutterEngine *flutter_instance) { + flutter_instances_.insert(flutter_instance); +} + +void RunLoop::UnregisterFlutterInstance( + flutter::FlutterEngine *flutter_instance) { + flutter_instances_.erase(flutter_instance); +} + +RunLoop::TimePoint RunLoop::ProcessFlutterMessages() { + TimePoint next_event_time = TimePoint::max(); + for (auto instance : flutter_instances_) { + std::chrono::nanoseconds wait_duration = instance->ProcessMessages(); + if (wait_duration != std::chrono::nanoseconds::max()) { + next_event_time = + std::min(next_event_time, TimePoint::clock::now() + wait_duration); + } + } + return next_event_time; +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/run_loop.h b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/run_loop.h new file mode 100644 index 00000000..7fe1aacc --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/run_loop.h @@ -0,0 +1,38 @@ +#ifndef RUNNER_RUN_LOOP_H_ +#define RUNNER_RUN_LOOP_H_ + +#include + +#include +#include + +// A runloop that will service events for Flutter instances as well +// as native messages. +class RunLoop { +public: + RunLoop(); + ~RunLoop(); + + // Prevent copying + RunLoop(RunLoop const &) = delete; + RunLoop &operator=(RunLoop const &) = delete; + + // Runs the run loop until the application quits. + void Run(); + + // Registers the given Flutter instance for event servicing. + void RegisterFlutterInstance(flutter::FlutterEngine *flutter_instance); + + // Unregisters the given Flutter instance from event servicing. + void UnregisterFlutterInstance(flutter::FlutterEngine *flutter_instance); + +private: + using TimePoint = std::chrono::steady_clock::time_point; + + // Processes all currently pending messages for registered Flutter instances. + TimePoint ProcessFlutterMessages(); + + std::set flutter_instances_; +}; + +#endif // RUNNER_RUN_LOOP_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/runner.exe.manifest b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..c977c4a4 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/utils.cpp b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/utils.cpp new file mode 100644 index 00000000..7758aabf --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/utils.cpp @@ -0,0 +1,63 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t **argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t *utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = + ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, -1, + nullptr, 0, nullptr, nullptr); + if (target_length == 0) { + return std::string(); + } + std::string utf8_string; + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, -1, utf8_string.data(), + target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/utils.h b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/utils.h new file mode 100644 index 00000000..ff43ce2c --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t *utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/win32_window.cpp b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/win32_window.cpp new file mode 100644 index 00000000..90ff01e5 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/win32_window.cpp @@ -0,0 +1,237 @@ +#include "win32_window.h" + +#include + +#include "resource.h" + +namespace { + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + FreeLibrary(user32_module); + } +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { +public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registar instance. + static WindowClassRegistrar *GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t *GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + +private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar *instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar *WindowClassRegistrar::instance_ = nullptr; + +const wchar_t *WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { ++g_active_window_count; } + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::CreateAndShow(const std::wstring &title, const Point &origin, + const Size &size) { + Destroy(); + + const wchar_t *window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + return OnCreate(); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window *that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window *Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { return window_handle_; } + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/win32_window.h b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/win32_window.h new file mode 100644 index 00000000..7b518125 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/example/windows/runner/win32_window.h @@ -0,0 +1,95 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { +public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates and shows a win32 window with |title| and position and size using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size to will treat the width height passed in to this function + // as logical pixels and scale to appropriate for the default monitor. Returns + // true if the window was created successfully. + bool CreateAndShow(const std::wstring &title, const Point &origin, + const Size &size); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + +protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + +private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responsponds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window *GetThisFromHandle(HWND const window) noexcept; + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus.podspec b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus.podspec new file mode 100644 index 00000000..6038dd29 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus.podspec @@ -0,0 +1,24 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'device_info_plus' + s.version = '0.0.1' + s.summary = 'Flutter Device Info Plus' + s.description = <<-DESC +Get current device information from within the Flutter application. +Downloaded by pub (not CocoaPods). + DESC + s.homepage = 'https://github.com/fluttercommunity/plus_plugins' + s.license = { :type => 'BSD', :file => '../LICENSE' } + s.author = { 'Flutter Community Team' => 'authors@fluttercommunity.dev' } + s.source = { :http => 'https://github.com/fluttercommunity/plus_plugins/tree/main/packages/device_info_plus' } + s.documentation_url = 'https://pub.dev/packages/device_info_plus' + s.source_files = 'device_info_plus/Sources/device_info_plus/**/*.{h,m}' + s.public_header_files = 'device_info_plus/Sources/device_info_plus/include/**/*.h' + s.dependency 'Flutter' + s.platform = :ios, '12.0' + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } + s.resource_bundles = {'device_info_plus_privacy' => ['device_info_plus/Sources/device_info_plus/PrivacyInfo.xcprivacy']} +end + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Package.swift b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Package.swift new file mode 100644 index 00000000..a4defdd7 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Package.swift @@ -0,0 +1,27 @@ +// swift-tools-version: 5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "device_info_plus", + platforms: [ + .iOS("12.0"), + ], + products: [ + .library(name: "device-info-plus", targets: ["device_info_plus"]) + ], + dependencies: [], + targets: [ + .target( + name: "device_info_plus", + dependencies: [], + resources: [ + .process("PrivacyInfo.xcprivacy"), + ], + cSettings: [ + .headerSearchPath("include/device_info_plus") + ] + ) + ] +) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Sources/device_info_plus/DeviceIdentifiers.m b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Sources/device_info_plus/DeviceIdentifiers.m new file mode 100644 index 00000000..fe877557 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Sources/device_info_plus/DeviceIdentifiers.m @@ -0,0 +1,230 @@ +// +// DeviceIdentifiers.m +// device_info_plus +// +// Created by Volodymyr on 06.11.2024. +// +#import "./include/device_info_plus/DeviceIdentifiers.h" + +@implementation DeviceIdentifiers + ++ (NSString *)userKnownDeviceModel:(NSString *)identifier { + if ([identifier isEqualToString:@"iPhone6,1"]) { + return @"iPhone 5s"; + } else if ([identifier isEqualToString:@"iPhone6,2"]) { + return @"iPhone 5s"; + } else if ([identifier isEqualToString:@"iPhone7,2"]) { + return @"iPhone 6"; + } else if ([identifier isEqualToString:@"iPhone7,1"]) { + return @"iPhone 6 Plus"; + } else if ([identifier isEqualToString:@"iPhone8,1"]) { + return @"iPhone 6s"; + } else if ([identifier isEqualToString:@"iPhone8,2"]) { + return @"iPhone 6s Plus"; + } else if ([identifier isEqualToString:@"iPhone9,1"] || + [identifier isEqualToString:@"iPhone9,3"]) { + return @"iPhone 7"; + } else if ([identifier isEqualToString:@"iPhone9,2"] || + [identifier isEqualToString:@"iPhone9,4"]) { + return @"iPhone 7 Plus"; + } else if ([identifier isEqualToString:@"iPhone8,4"]) { + return @"iPhone SE"; + } else if ([identifier isEqualToString:@"iPhone10,1"] || + [identifier isEqualToString:@"iPhone10,4"]) { + return @"iPhone 8"; + } else if ([identifier isEqualToString:@"iPhone10,2"] || + [identifier isEqualToString:@"iPhone10,5"]) { + return @"iPhone 8 Plus"; + } else if ([identifier isEqualToString:@"iPhone10,3"] || + [identifier isEqualToString:@"iPhone10,6"]) { + return @"iPhone X"; + } else if ([identifier isEqualToString:@"iPhone11,2"]) { + return @"iPhone XS"; + } else if ([identifier isEqualToString:@"iPhone11,4"] || + [identifier isEqualToString:@"iPhone11,6"]) { + return @"iPhone XS Max"; + } else if ([identifier isEqualToString:@"iPhone11,8"]) { + return @"iPhone XR"; + } else if ([identifier isEqualToString:@"iPhone12,1"]) { + return @"iPhone 11"; + } else if ([identifier isEqualToString:@"iPhone12,3"]) { + return @"iPhone 11 Pro"; + } else if ([identifier isEqualToString:@"iPhone12,5"]) { + return @"iPhone 11 Pro Max"; + } else if ([identifier isEqualToString:@"iPhone12,8"]) { + return @"iPhone SE 2"; + } else if ([identifier isEqualToString:@"iPhone13,2"]) { + return @"iPhone 12"; + } else if ([identifier isEqualToString:@"iPhone13,1"]) { + return @"iPhone 12 Mini"; + } else if ([identifier isEqualToString:@"iPhone13,3"]) { + return @"iPhone 12 Pro"; + } else if ([identifier isEqualToString:@"iPhone13,4"]) { + return @"iPhone 12 Pro Max"; + } else if ([identifier isEqualToString:@"iPhone14,5"]) { + return @"iPhone 13"; + } else if ([identifier isEqualToString:@"iPhone14,4"]) { + return @"iPhone 13 Mini"; + } else if ([identifier isEqualToString:@"iPhone14,2"]) { + return @"iPhone 13 Pro"; + } else if ([identifier isEqualToString:@"iPhone14,3"]) { + return @"iPhone 13 Pro Max"; + } else if ([identifier isEqualToString:@"iPhone14,6"]) { + return @"iPhone SE 3"; + } else if ([identifier isEqualToString:@"iPhone14,7"]) { + return @"iPhone 14"; + } else if ([identifier isEqualToString:@"iPhone14,8"]) { + return @"iPhone 14 Plus"; + } else if ([identifier isEqualToString:@"iPhone15,2"]) { + return @"iPhone 14 Pro"; + } else if ([identifier isEqualToString:@"iPhone15,3"]) { + return @"iPhone 14 Pro Max"; + } else if ([identifier isEqualToString:@"iPhone15,4"]) { + return @"iPhone 15"; + } else if ([identifier isEqualToString:@"iPhone15,5"]) { + return @"iPhone 15 Plus"; + } else if ([identifier isEqualToString:@"iPhone16,1"]) { + return @"iPhone 15 Pro"; + } else if ([identifier isEqualToString:@"iPhone16,2"]) { + return @"iPhone 15 Pro Max"; + } else if ([identifier isEqualToString:@"iPhone17,3"]) { + return @"iPhone 16"; + } else if ([identifier isEqualToString:@"iPhone17,4"]) { + return @"iPhone 16 Plus"; + } else if ([identifier isEqualToString:@"iPhone17,1"]) { + return @"iPhone 16 Pro"; + } else if ([identifier isEqualToString:@"iPhone17,2"]) { + return @"iPhone 16 Pro Max"; + } else if ([identifier isEqualToString:@"iPhone17,5"]) { + return @"iPhone 16e"; + } else if ([identifier isEqualToString:@"iPhone18,3"]) { + return @"iPhone 17"; + } else if ([identifier isEqualToString:@"iPhone18,1"]) { + return @"iPhone 17 Pro"; + } else if ([identifier isEqualToString:@"iPhone18,2"]) { + return @"iPhone 17 Pro Max"; + } else if ([identifier isEqualToString:@"iPhone18,4"]) { + return @"iPhone Air"; + // iPads + } else if ([identifier isEqualToString:@"iPad4,1"] || + [identifier isEqualToString:@"iPad4,2"] || + [identifier isEqualToString:@"iPad4,3"]) { + return @"iPad Air"; + } else if ([identifier isEqualToString:@"iPad5,3"] || + [identifier isEqualToString:@"iPad5,4"]) { + return @"iPad Air 2"; + } else if ([identifier isEqualToString:@"iPad6,11"] || + [identifier isEqualToString:@"iPad6,12"]) { + return @"iPad 5"; + } else if ([identifier isEqualToString:@"iPad7,5"] || + [identifier isEqualToString:@"iPad7,6"]) { + return @"iPad 6"; + } else if ([identifier isEqualToString:@"iPad11,3"] || + [identifier isEqualToString:@"iPad11,4"]) { + return @"iPad Air 3"; + } else if ([identifier isEqualToString:@"iPad7,11"] || + [identifier isEqualToString:@"iPad7,12"]) { + return @"iPad 7"; + } else if ([identifier isEqualToString:@"iPad11,6"] || + [identifier isEqualToString:@"iPad11,7"]) { + return @"iPad 8"; + } else if ([identifier isEqualToString:@"iPad12,1"] || + [identifier isEqualToString:@"iPad12,2"]) { + return @"iPad 9"; + } else if ([identifier isEqualToString:@"iPad13,18"] || + [identifier isEqualToString:@"iPad13,19"]) { + return @"iPad 10"; + } else if ([identifier isEqualToString:@"iPad13,1"] || + [identifier isEqualToString:@"iPad13,2"]) { + return @"iPad Air 4"; + } else if ([identifier isEqualToString:@"iPad13,16"] || + [identifier isEqualToString:@"iPad13,17"]) { + return @"iPad Air 5"; + } else if ([identifier isEqualToString:@"iPad14,8"] || + [identifier isEqualToString:@"iPad14,9"]) { + return @"iPad Air 11-Inch M2"; + } else if ([identifier isEqualToString:@"iPad14,10"] || + [identifier isEqualToString:@"iPad14,11"]) { + return @"iPad Air 13-Inch M2"; + } else if ([identifier isEqualToString:@"iPad2,5"] || + [identifier isEqualToString:@"iPad2,6"] || + [identifier isEqualToString:@"iPad2,7"]) { + return @"iPad Mini"; + } else if ([identifier isEqualToString:@"iPad4,4"] || + [identifier isEqualToString:@"iPad4,5"] || + [identifier isEqualToString:@"iPad4,6"]) { + return @"iPad Mini 2"; + } else if ([identifier isEqualToString:@"iPad4,7"] || + [identifier isEqualToString:@"iPad4,8"] || + [identifier isEqualToString:@"iPad4,9"]) { + return @"iPad Mini 3"; + } else if ([identifier isEqualToString:@"iPad5,1"] || + [identifier isEqualToString:@"iPad5,2"]) { + return @"iPad Mini 4"; + } else if ([identifier isEqualToString:@"iPad11,1"] || + [identifier isEqualToString:@"iPad11,2"]) { + return @"iPad Mini 5"; + } else if ([identifier isEqualToString:@"iPad14,1"] || + [identifier isEqualToString:@"iPad14,2"]) { + return @"iPad Mini 6"; + } else if ([identifier isEqualToString:@"iPad6,3"] || + [identifier isEqualToString:@"iPad6,4"]) { + return @"iPad Pro 9-Inch"; + } else if ([identifier isEqualToString:@"iPad6,7"] || + [identifier isEqualToString:@"iPad6,8"]) { + return @"iPad Pro 12-Inch"; + } else if ([identifier isEqualToString:@"iPad7,1"] || + [identifier isEqualToString:@"iPad7,2"]) { + return @"iPad Pro 12-Inch 2"; + } else if ([identifier isEqualToString:@"iPad7,3"] || + [identifier isEqualToString:@"iPad7,4"]) { + return @"iPad Pro 10-Inch"; + } else if ([identifier isEqualToString:@"iPad8,1"] || + [identifier isEqualToString:@"iPad8,2"] || + [identifier isEqualToString:@"iPad8,3"] || + [identifier isEqualToString:@"iPad8,4"]) { + return @"iPad Pro 11-Inch"; + } else if ([identifier isEqualToString:@"iPad8,5"] || + [identifier isEqualToString:@"iPad8,6"] || + [identifier isEqualToString:@"iPad8,7"] || + [identifier isEqualToString:@"iPad8,8"]) { + return @"iPad Pro 12-Inch 3"; + } else if ([identifier isEqualToString:@"iPad8,9"] || + [identifier isEqualToString:@"iPad8,10"]) { + return @"iPad Pro 11-Inch 2"; + } else if ([identifier isEqualToString:@"iPad8,11"] || + [identifier isEqualToString:@"iPad8,12"]) { + return @"iPad Pro 12-Inch 4"; + } else if ([identifier isEqualToString:@"iPad13,4"] || + [identifier isEqualToString:@"iPad13,5"] || + [identifier isEqualToString:@"iPad13,6"] || + [identifier isEqualToString:@"iPad13,7"]) { + return @"iPad Pro 11-Inch 3"; + } else if ([identifier isEqualToString:@"iPad13,8"] || + [identifier isEqualToString:@"iPad13,9"] || + [identifier isEqualToString:@"iPad13,10"] || + [identifier isEqualToString:@"iPad13,11"]) { + return @"iPad Pro 12-Inch 5"; + } else if ([identifier isEqualToString:@"iPad14,3"] || + [identifier isEqualToString:@"iPad14,4"]) { + return @"iPad Pro 11-Inch 4"; + } else if ([identifier isEqualToString:@"iPad14,5"] || + [identifier isEqualToString:@"iPad14,6"]) { + return @"iPad Pro 12-Inch 6"; + } else if ([identifier isEqualToString:@"iPad16,3"] || + [identifier isEqualToString:@"iPad16,4"]) { + return @"iPad Pro 11-Inch (M4)"; + } else if ([identifier isEqualToString:@"iPad16,5"] || + [identifier isEqualToString:@"iPad16,6"]) { + return @"iPad Pro 13-Inch (M4)"; + } else if ([identifier isEqualToString:@"iPad17,1"] || + [identifier isEqualToString:@"iPad17,2"]) { + return @"iPad Pro 11-Inch (M5)"; + } else if ([identifier isEqualToString:@"iPad17,3"] || + [identifier isEqualToString:@"iPad17,4"]) { + return @"iPad Pro 13-Inch (M5)"; + } else { + return @"Unknown device"; + } +} +@end diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Sources/device_info_plus/FPPDeviceInfoPlusPlugin.m b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Sources/device_info_plus/FPPDeviceInfoPlusPlugin.m new file mode 100644 index 00000000..9e3ee569 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Sources/device_info_plus/FPPDeviceInfoPlusPlugin.m @@ -0,0 +1,112 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "./include/device_info_plus/FPPDeviceInfoPlusPlugin.h" +#import "./include/device_info_plus/DeviceIdentifiers.h" +#import +#import + +@implementation FPPDeviceInfoPlusPlugin ++ (void)registerWithRegistrar:(NSObject *)registrar { + FlutterMethodChannel *channel = [FlutterMethodChannel + methodChannelWithName:@"dev.fluttercommunity.plus/device_info" + binaryMessenger:[registrar messenger]]; + FPPDeviceInfoPlusPlugin *instance = [[FPPDeviceInfoPlusPlugin alloc] init]; + [registrar addMethodCallDelegate:instance channel:channel]; +} + +- (void)handleMethodCall:(FlutterMethodCall *)call + result:(FlutterResult)result { + if ([@"getDeviceInfo" isEqualToString:call.method]) { + UIDevice *device = [UIDevice currentDevice]; + struct utsname un; + uname(&un); + + NSNumber *isPhysicalNumber = + [NSNumber numberWithBool:[self isDevicePhysical]]; + NSProcessInfo *info = [NSProcessInfo processInfo]; + NSNumber *isiOSAppOnMac = [NSNumber numberWithBool:NO]; + if (@available(iOS 14.0, *)) { + isiOSAppOnMac = [NSNumber numberWithBool:[info isiOSAppOnMac]]; + } + NSError *error = nil; + NSDictionary *fsAttributes = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:&error]; + NSNumber *freeSize = [NSNumber numberWithInt:-1]; + NSNumber *totalSize = [NSNumber numberWithInt:-1]; + if(fsAttributes) { + freeSize = fsAttributes[NSFileSystemFreeSize]; + totalSize = fsAttributes[NSFileSystemSize]; + } + + NSString *machine; + NSString *deviceName; + if ([self isDevicePhysical]) { + machine = @(un.machine); + } else { + machine = [info environment][@"SIMULATOR_MODEL_IDENTIFIER"]; + } + deviceName = [DeviceIdentifiers userKnownDeviceModel:machine]; + + NSNumber *physicalRamSize = @([NSProcessInfo processInfo].physicalMemory / 1048576); // Mb + NSNumber *availableRamSize = @([self availableMemoryInbMB]); + + result(@{ + @"name" : [device name], + @"systemName" : [device systemName], + @"systemVersion" : [device systemVersion], + @"model" : [device model], + @"localizedModel" : [device localizedModel], + @"modelName" : deviceName, + @"identifierForVendor" : [[device identifierForVendor] UUIDString] + ?: [NSNull null], + @"freeDiskSize" : freeSize, + @"totalDiskSize" : totalSize, + @"isPhysicalDevice" : isPhysicalNumber, + @"isiOSAppOnMac" : isiOSAppOnMac, + @"physicalRamSize" : physicalRamSize, + @"availableRamSize" : availableRamSize, + @"utsname" : @{ + @"sysname" : @(un.sysname), + @"nodename" : @(un.nodename), + @"release" : @(un.release), + @"version" : @(un.version), + @"machine" : machine, + } + }); + } else { + result(FlutterMethodNotImplemented); + } +} + +// Return available memory in megabytes +- (int)availableMemoryInbMB { + mach_port_t host_port = mach_host_self(); + mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t); + + vm_size_t page_size; + host_page_size(host_port, &page_size); + + vm_statistics_data_t vm_stat; + if (host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) != KERN_SUCCESS) { + // Failed to fetch vm statistics + return -1; + } + + natural_t mem_free = vm_stat.free_count * page_size; + return mem_free / 1048576; +} + +// Return value is false if code is run on a simulator +- (BOOL)isDevicePhysical { + BOOL isPhysicalDevice = NO; +#if TARGET_OS_SIMULATOR + isPhysicalDevice = NO; +#else + isPhysicalDevice = YES; +#endif + + return isPhysicalDevice; +} + +@end diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Sources/device_info_plus/PrivacyInfo.xcprivacy b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Sources/device_info_plus/PrivacyInfo.xcprivacy new file mode 100644 index 00000000..a34b7e2e --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Sources/device_info_plus/PrivacyInfo.xcprivacy @@ -0,0 +1,14 @@ + + + + + NSPrivacyTrackingDomains + + NSPrivacyAccessedAPITypes + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Sources/device_info_plus/include/device_info_plus/DeviceIdentifiers.h b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Sources/device_info_plus/include/device_info_plus/DeviceIdentifiers.h new file mode 100644 index 00000000..0f5c8d70 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Sources/device_info_plus/include/device_info_plus/DeviceIdentifiers.h @@ -0,0 +1,13 @@ +// +// DeviceIdentifiers.h +// device_info_plus +// +// Created by Volodymyr on 06.11.2024. +// +#import + +@interface DeviceIdentifiers : NSObject + ++ (NSString *)userKnownDeviceModel:(NSString *)identifier; + +@end diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Sources/device_info_plus/include/device_info_plus/FPPDeviceInfoPlusPlugin.h b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Sources/device_info_plus/include/device_info_plus/FPPDeviceInfoPlusPlugin.h new file mode 100644 index 00000000..430e81ce --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/ios/device_info_plus/Sources/device_info_plus/include/device_info_plus/FPPDeviceInfoPlusPlugin.h @@ -0,0 +1,8 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import + +@interface FPPDeviceInfoPlusPlugin : NSObject +@end diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/device_info_plus.dart b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/device_info_plus.dart new file mode 100644 index 00000000..f5acdb5c --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/device_info_plus.dart @@ -0,0 +1,141 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:io'; + +import 'package:device_info_plus_platform_interface/device_info_plus_platform_interface.dart'; +import 'package:flutter/foundation.dart'; + +import 'src/model/android_device_info.dart'; +import 'src/model/ios_device_info.dart'; +import 'src/model/linux_device_info.dart'; +import 'src/model/macos_device_info.dart'; +import 'src/model/web_browser_info.dart'; +import 'src/model/windows_device_info.dart'; + +export 'package:device_info_plus_platform_interface/device_info_plus_platform_interface.dart' + show BaseDeviceInfo; + +export 'src/model/android_device_info.dart'; +export 'src/model/ios_device_info.dart'; +export 'src/model/linux_device_info.dart'; +export 'src/model/macos_device_info.dart'; +export 'src/model/web_browser_info.dart'; +export 'src/model/windows_device_info.dart'; + +export 'src/device_info_plus_linux.dart' + if (dart.library.js_interop) 'src/device_info_plus_web.dart'; +export 'src/device_info_plus_windows.dart' + if (dart.library.js_interop) 'src/device_info_plus_web.dart'; + +/// Provides device and operating system information. +class DeviceInfoPlugin { + /// No work is done when instantiating the plugin. It's safe to call this + /// repeatedly or in performance-sensitive blocks. + DeviceInfoPlugin(); + + // This is to manually endorse the Linux plugin until automatic registration + // of dart plugins is implemented. + // See https://github.com/flutter/flutter/issues/52267 for more details. + static DeviceInfoPlatform get _platform { + return DeviceInfoPlatform.instance; + } + + /// This information does not change from call to call. Cache it. + AndroidDeviceInfo? _cachedAndroidDeviceInfo; + + /// Information derived from `android.os.Build`. + /// + /// See: https://developer.android.com/reference/android/os/Build.html + Future get androidInfo async => + _cachedAndroidDeviceInfo ??= AndroidDeviceInfo.fromMap( + (await _platform.deviceInfo()).data, + ); + + /// This information does not change from call to call. Cache it. + IosDeviceInfo? _cachedIosDeviceInfo; + + /// Information derived from `UIDevice`. + /// + /// See: https://developer.apple.com/documentation/uikit/uidevice + Future get iosInfo async => + _cachedIosDeviceInfo ??= IosDeviceInfo.fromMap( + (await _platform.deviceInfo()).data, + ); + + /// This information does not change from call to call. Cache it. + LinuxDeviceInfo? _cachedLinuxDeviceInfo; + + /// Information derived from `/etc/os-release`. + /// + /// See: https://www.freedesktop.org/software/systemd/man/os-release.html + Future get linuxInfo async => + _cachedLinuxDeviceInfo ??= + await _platform.deviceInfo() as LinuxDeviceInfo; + + /// This information does not change from call to call. Cache it. + WebBrowserInfo? _cachedWebBrowserInfo; + + /// Information derived from `Navigator`. + Future get webBrowserInfo async => + _cachedWebBrowserInfo ??= await _platform.deviceInfo() as WebBrowserInfo; + + /// This information does not change from call to call. Cache it. + MacOsDeviceInfo? _cachedMacosDeviceInfo; + + /// Returns device information for macos. Information sourced from Sysctl. + Future get macOsInfo async => + _cachedMacosDeviceInfo ??= MacOsDeviceInfo.fromMap( + (await _platform.deviceInfo()).data, + ); + + WindowsDeviceInfo? _cachedWindowsDeviceInfo; + + /// Returns device information for Windows. + Future get windowsInfo async => + _cachedWindowsDeviceInfo ??= + await _platform.deviceInfo() as WindowsDeviceInfo; + + /// Returns device information for the current platform. + Future get deviceInfo async { + if (kIsWeb) { + return webBrowserInfo; + } else { + if (Platform.isAndroid) { + return androidInfo; + } else if (Platform.isIOS) { + return iosInfo; + } else if (Platform.isLinux) { + return linuxInfo; + } else if (Platform.isMacOS) { + return macOsInfo; + } else if (Platform.isWindows) { + return windowsInfo; + } + } + // allow for extension of the plugin + return _platform.deviceInfo(); + } + + /// Initializes the application metadata with mock values for testing. + @visibleForTesting + static DeviceInfoPlugin setMockInitialValues({ + AndroidDeviceInfo? androidDeviceInfo, + IosDeviceInfo? iosDeviceInfo, + LinuxDeviceInfo? linuxDeviceInfo, + WebBrowserInfo? webBrowserInfo, + MacOsDeviceInfo? macOsDeviceInfo, + WindowsDeviceInfo? windowsDeviceInfo, + }) { + final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin(); + deviceInfoPlugin._cachedAndroidDeviceInfo = androidDeviceInfo; + deviceInfoPlugin._cachedIosDeviceInfo = iosDeviceInfo; + deviceInfoPlugin._cachedLinuxDeviceInfo = linuxDeviceInfo; + deviceInfoPlugin._cachedWebBrowserInfo = webBrowserInfo; + deviceInfoPlugin._cachedMacosDeviceInfo = macOsDeviceInfo; + deviceInfoPlugin._cachedWindowsDeviceInfo = windowsDeviceInfo; + return deviceInfoPlugin; + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/device_info_plus_linux.dart b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/device_info_plus_linux.dart new file mode 100644 index 00000000..bc4b42d3 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/device_info_plus_linux.dart @@ -0,0 +1,107 @@ +import 'dart:async'; + +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:device_info_plus_platform_interface/device_info_plus_platform_interface.dart'; +import 'package:file/file.dart'; +import 'package:file/local.dart'; +import 'package:meta/meta.dart'; + +/// See [DeviceInfoPlatform] +class DeviceInfoPlusLinuxPlugin extends DeviceInfoPlatform { + /// Register this dart class as the platform implementation for linux + static void registerWith() { + DeviceInfoPlatform.instance = DeviceInfoPlusLinuxPlugin(); + } + + LinuxDeviceInfo? _cache; + final FileSystem _fileSystem; + + /// + DeviceInfoPlusLinuxPlugin({@visibleForTesting FileSystem? fileSystem}) + : _fileSystem = fileSystem ?? const LocalFileSystem(); + + @override + Future deviceInfo() async { + return _cache ??= await _getInfo(); + } + + Future linuxInfo() async { + return (await deviceInfo()) as LinuxDeviceInfo; + } + + Future _getInfo() async { + final os = await _getOsRelease() ?? {}; + final lsb = await _getLsbRelease() ?? {}; + final machineId = await _getMachineId(); + + return LinuxDeviceInfo( + name: os['NAME'] ?? 'Linux', + version: os['VERSION'] ?? lsb['LSB_VERSION'], + id: os['ID'] ?? lsb['DISTRIB_ID'] ?? 'linux', + idLike: os['ID_LIKE']?.split(' '), + versionCodename: os['VERSION_CODENAME'] ?? lsb['DISTRIB_CODENAME'], + versionId: os['VERSION_ID'] ?? lsb['DISTRIB_RELEASE'], + prettyName: os['PRETTY_NAME'] ?? lsb['DISTRIB_DESCRIPTION'] ?? 'Linux', + buildId: os['BUILD_ID'], + variant: os['VARIANT'], + variantId: os['VARIANT_ID'], + machineId: machineId, + ); + } + + Future?> _getOsRelease() { + return _tryReadKeyValues('/etc/os-release').then( + (value) async => value ?? await _tryReadKeyValues('/usr/lib/os-release'), + ); + } + + Future?> _getLsbRelease() { + return _tryReadKeyValues('/etc/lsb-release'); + } + + Future _getMachineId() { + return _tryReadValue('/etc/machine-id'); + } + + Future _tryReadValue(String path) { + return _fileSystem + .file(path) + .readAsString() + .then((str) => str.trim(), onError: (_) => null); + } + + Future?> _tryReadKeyValues(String path) { + return _fileSystem + .file(path) + .readAsLines() + .then((lines) => lines.toKeyValues(), onError: (_) => null); + } +} + +extension _Unquote on String { + String removePrefix(String prefix) { + if (!startsWith(prefix)) return this; + return substring(prefix.length); + } + + String removeSuffix(String suffix) { + if (!endsWith(suffix)) return this; + return substring(0, length - suffix.length); + } + + String unquote() { + return removePrefix('"').removeSuffix('"'); + } +} + +extension _KeyValues on List { + Map toKeyValues() { + return Map.fromEntries( + map((line) { + final parts = line.split('='); + if (parts.length != 2) return MapEntry(line, null); + return MapEntry(parts.first, parts.last.unquote()); + }), + ); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/device_info_plus_macos.dart b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/device_info_plus_macos.dart new file mode 100644 index 00000000..39e7bb81 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/device_info_plus_macos.dart @@ -0,0 +1,2 @@ +// ignore: dangling_library_doc_comments +/// The platform interface handles the method channel calls. This file exists to silence errors on pub. diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/device_info_plus_web.dart b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/device_info_plus_web.dart new file mode 100644 index 00000000..c9f153a1 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/device_info_plus_web.dart @@ -0,0 +1,59 @@ +import 'dart:async'; +import 'dart:js_interop'; +import 'package:web/web.dart' as html show window, Navigator; + +import 'package:device_info_plus_platform_interface/device_info_plus_platform_interface.dart'; +import 'package:flutter_web_plugins/flutter_web_plugins.dart'; + +import 'model/web_browser_info.dart'; + +/// The web implementation of the BatteryPlusPlatform of the BatteryPlus plugin. +class DeviceInfoPlusWebPlugin extends DeviceInfoPlatform { + /// Constructs a DeviceInfoPlusPlugin. + DeviceInfoPlusWebPlugin(navigator) : _navigator = navigator; + + final html.Navigator _navigator; + + /// Factory method that initializes the DeviceInfoPlus plugin platform + /// with an instance of the plugin for the web. + static void registerWith(Registrar registrar) { + DeviceInfoPlatform.instance = DeviceInfoPlusWebPlugin( + html.window.navigator, + ); + } + + @override + Future deviceInfo() { + return Future.value( + WebBrowserInfo.fromMap({ + 'appCodeName': _navigator.appCodeName, + 'appName': _navigator.appName, + 'appVersion': _navigator.appVersion, + 'deviceMemory': _navigator.safeDeviceMemory, + 'language': _navigator.language, + 'languages': _navigator.languages.toDart, + 'platform': _navigator.platform, + 'product': _navigator.product, + 'productSub': _navigator.productSub, + 'userAgent': _navigator.userAgent, + 'vendor': _navigator.vendor, + 'vendorSub': _navigator.vendorSub, + 'hardwareConcurrency': _navigator.hardwareConcurrency, + 'maxTouchPoints': _navigator.maxTouchPoints, + }), + ); + } +} + +/// Some Navigator properties are not fully supported in all browsers. +/// However, package:web does not provide a safe way to access these properties, +/// and assumes they are always not null. +/// +/// This extension provides a safe way to access these properties. +/// +/// See: https://github.com/dart-lang/web/issues/326 +/// https://github.com/fluttercommunity/plus_plugins/issues/3391 +extension SafeNavigationGetterExtensions on html.Navigator { + @JS('deviceMemory') + external double? get safeDeviceMemory; +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/device_info_plus_windows.dart b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/device_info_plus_windows.dart new file mode 100644 index 00000000..d4385abb --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/device_info_plus_windows.dart @@ -0,0 +1,187 @@ +/// The Windows implementation of `device_info_plus`. +library; + +import 'dart:ffi'; +import 'dart:typed_data'; +import 'dart:developer' as developer; + +import 'package:device_info_plus_platform_interface/device_info_plus_platform_interface.dart'; +import 'package:ffi/ffi.dart'; +import 'package:meta/meta.dart'; +import 'package:win32/win32.dart'; +import 'package:win32_registry/win32_registry.dart'; + +import 'model/windows_device_info.dart'; + +/// The Windows implementation of [DeviceInfoPlatform]. +class DeviceInfoPlusWindowsPlugin extends DeviceInfoPlatform { + /// Register this dart class as the platform implementation for windows + static void registerWith() { + DeviceInfoPlatform.instance = DeviceInfoPlusWindowsPlugin(); + } + + WindowsDeviceInfo? _cache; + + // In a well-meaning but somewhat misguided attempt to reduce apps from using + // version numbers for feature detection, most version number APIs don't give + // expected results on Windows 8 and above. RtlGetVersion is reliable and + // stable, but as a kernel API is documented in the Windows DDK (Driver + // Development Kit), rather than the SDK. As such, it's not included in + // package:win32, so we have to manually define it here. + // + // ignore: non_constant_identifier_names + void Function(Pointer) RtlGetVersion = DynamicLibrary.open( + 'ntdll.dll', + ).lookupFunction< + Void Function(Pointer), + void Function(Pointer) + >('RtlGetVersion'); + + /// Returns a [WindowsDeviceInfo] with information about the device. + @override + Future deviceInfo() { + return Future.value(_cache ??= getInfo()); + } + + @visibleForTesting + WindowsDeviceInfo getInfo() { + final systemInfo = calloc(); + final osVersionInfo = + calloc() + ..ref.dwOSVersionInfoSize = sizeOf(); + + try { + final currentVersionKey = Registry.openPath( + RegistryHive.localMachine, + path: r'SOFTWARE\Microsoft\Windows NT\CurrentVersion', + ); + final buildLab = currentVersionKey.getStringValue('BuildLab') ?? ''; + final buildLabEx = currentVersionKey.getStringValue('BuildLabEx') ?? ''; + final digitalProductId = + currentVersionKey.getBinaryValue('DigitalProductId') ?? + Uint8List.fromList([]); + final displayVersion = + currentVersionKey.getStringValue('DisplayVersion') ?? ''; + final editionId = currentVersionKey.getStringValue('EditionID') ?? ''; + final installDate = DateTime.fromMillisecondsSinceEpoch( + 1000 * (currentVersionKey.getIntValue('InstallDate') ?? 0), + ); + final productId = currentVersionKey.getStringValue('ProductID') ?? ''; + var productName = currentVersionKey.getStringValue('ProductName') ?? ''; + final registeredOwner = + currentVersionKey.getStringValue('RegisteredOwner') ?? ''; + final releaseId = currentVersionKey.getStringValue('ReleaseId') ?? ''; + + final sqmClientKey = Registry.openPath( + RegistryHive.localMachine, + path: r'SOFTWARE\Microsoft\SQMClient', + ); + final machineId = sqmClientKey.getStringValue('MachineId') ?? ''; + + GetSystemInfo(systemInfo); + + // Use `RtlGetVersion` from `ntdll.dll` to get the Windows version. + RtlGetVersion(osVersionInfo); + + // Handle [productName] for Windows 11 separately (as per Raymond Chen's comment). + // https://stackoverflow.com/questions/69460588/how-can-i-find-the-windows-product-name-in-windows-11 + if (osVersionInfo.ref.dwBuildNumber >= 22000) { + productName = productName.replaceAll('10', '11'); + } + final data = WindowsDeviceInfo( + numberOfCores: systemInfo.ref.dwNumberOfProcessors, + computerName: getComputerName(), + systemMemoryInMegabytes: getSystemMemoryInMegabytes(), + userName: getUserName(), + majorVersion: osVersionInfo.ref.dwMajorVersion, + minorVersion: osVersionInfo.ref.dwMinorVersion, + buildNumber: osVersionInfo.ref.dwBuildNumber, + platformId: osVersionInfo.ref.dwPlatformId, + csdVersion: osVersionInfo.ref.szCSDVersion, + servicePackMajor: osVersionInfo.ref.wServicePackMajor, + servicePackMinor: osVersionInfo.ref.wServicePackMinor, + suitMask: osVersionInfo.ref.wSuiteMask, + productType: osVersionInfo.ref.wProductType, + reserved: osVersionInfo.ref.wReserved, + buildLab: buildLab, + buildLabEx: buildLabEx, + digitalProductId: digitalProductId, + displayVersion: displayVersion, + editionId: editionId, + installDate: installDate, + productId: productId, + productName: productName, + registeredOwner: registeredOwner, + releaseId: releaseId, + deviceId: machineId, + ); + return data; + } finally { + free(systemInfo); + free(osVersionInfo); + } + } + + @visibleForTesting + int getSystemMemoryInMegabytes() { + final memoryInKilobytes = calloc(); + try { + final result = GetPhysicallyInstalledSystemMemory(memoryInKilobytes); + if (result != 0) { + return memoryInKilobytes.value ~/ 1024; + } else { + developer.log('Failed to get system memory', error: GetLastError()); + return 0; + } + } finally { + free(memoryInKilobytes); + } + } + + @visibleForTesting + String getComputerName() { + // We call this a first time to get the length of the string in characters, + // so we can allocate sufficient memory. + final nSize = calloc(); + GetComputerNameEx(ComputerNameDnsFullyQualified, nullptr, nSize); + + // Now allocate memory for a native string and call this a second time. + final lpBuffer = wsalloc(nSize.value); + try { + final result = GetComputerNameEx( + ComputerNameDnsFullyQualified, + lpBuffer, + nSize, + ); + + if (result != 0) { + return lpBuffer.toDartString(); + } else { + developer.log('Failed to get computer name', error: GetLastError()); + return ""; + } + } finally { + free(lpBuffer); + free(nSize); + } + } + + @visibleForTesting + String getUserName() { + const maxLength = 256; // defined as UNLEN in Lmcons.h + final lpBuffer = wsalloc(maxLength + 1); // allow for terminating null + final pcbBuffer = calloc()..value = maxLength + 1; + try { + final result = GetUserName(lpBuffer, pcbBuffer); + if (result != 0) { + return lpBuffer.toDartString(); + } else { + developer.log('Failed to get user name', error: GetLastError()); + return ""; + } + } finally { + free(pcbBuffer); + free(lpBuffer); + } + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/android_device_info.dart b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/android_device_info.dart new file mode 100644 index 00000000..5fae3696 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/android_device_info.dart @@ -0,0 +1,395 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:device_info_plus_platform_interface/model/base_device_info.dart'; +import 'package:meta/meta.dart'; + +/// Information derived from `android.os.Build`. +/// +/// See: https://developer.android.com/reference/android/os/Build.html +class AndroidDeviceInfo extends BaseDeviceInfo { + AndroidDeviceInfo._({ + required Map data, + required this.version, + required this.board, + required this.bootloader, + required this.brand, + required this.device, + required this.display, + required this.fingerprint, + required this.hardware, + required this.host, + required this.id, + required this.manufacturer, + required this.model, + required this.product, + required this.name, + required List supported32BitAbis, + required List supported64BitAbis, + required List supportedAbis, + required this.tags, + required this.type, + required this.isPhysicalDevice, + required this.freeDiskSize, + required this.totalDiskSize, + required List systemFeatures, + required this.isLowRamDevice, + required this.physicalRamSize, + required this.availableRamSize, + }) : supported32BitAbis = List.unmodifiable(supported32BitAbis), + supported64BitAbis = List.unmodifiable(supported64BitAbis), + supportedAbis = List.unmodifiable(supportedAbis), + systemFeatures = List.unmodifiable(systemFeatures), + super(data); + + /// Android operating system version values derived from `android.os.Build.VERSION`. + final AndroidBuildVersion version; + + /// The name of the underlying board, like "goldfish". + /// https://developer.android.com/reference/android/os/Build#BOARD + final String board; + + /// The system bootloader version number. + /// https://developer.android.com/reference/android/os/Build#BOOTLOADER + final String bootloader; + + /// The consumer-visible brand with which the product/hardware will be associated, if any. + /// https://developer.android.com/reference/android/os/Build#BRAND + final String brand; + + /// The name of the industrial design. + /// https://developer.android.com/reference/android/os/Build#DEVICE + final String device; + + /// A build ID string meant for displaying to the user. + /// https://developer.android.com/reference/android/os/Build#DISPLAY + final String display; + + /// A string that uniquely identifies this build. + /// https://developer.android.com/reference/android/os/Build#FINGERPRINT + final String fingerprint; + + /// The name of the hardware (from the kernel command line or /proc). + /// https://developer.android.com/reference/android/os/Build#HARDWARE + final String hardware; + + /// Hostname. + /// https://developer.android.com/reference/android/os/Build#HOST + final String host; + + /// Either a changelist number, or a label like "M4-rc20". + /// https://developer.android.com/reference/android/os/Build#ID + final String id; + + /// The manufacturer of the product/hardware. + /// https://developer.android.com/reference/android/os/Build#MANUFACTURER + final String manufacturer; + + /// The end-user-visible name for the end product. + /// https://developer.android.com/reference/android/os/Build#MODEL + final String model; + + /// The name of the overall product. + /// https://developer.android.com/reference/android/os/Build#PRODUCT + final String product; + + /// The name of the device. + /// https://developer.android.com/reference/android/provider/Settings.Global#DEVICE_NAME + final String name; + + /// An ordered list of 32 bit ABIs supported by this device. + /// Available only on Android L (API 21) and newer + /// https://developer.android.com/reference/android/os/Build#SUPPORTED_32_BIT_ABIS + final List supported32BitAbis; + + /// An ordered list of 64 bit ABIs supported by this device. + /// Available only on Android L (API 21) and newer + /// https://developer.android.com/reference/android/os/Build#SUPPORTED_64_BIT_ABIS + final List supported64BitAbis; + + /// An ordered list of ABIs supported by this device. + /// Available only on Android L (API 21) and newer + /// https://developer.android.com/reference/android/os/Build#SUPPORTED_ABIS + final List supportedAbis; + + /// Comma-separated tags describing the build, like "unsigned,debug". + /// https://developer.android.com/reference/android/os/Build#TAGS + final String tags; + + /// The type of build, like "user" or "eng". + /// https://developer.android.com/reference/android/os/Build#TYPE + final String type; + + /// `false` if the application is running in an emulator, `true` otherwise. + final bool isPhysicalDevice; + + /// Available disk size in bytes + /// + /// https://developer.android.com/reference/android/os/StatFs#getFreeBytes() + final int freeDiskSize; + + /// Total disk size in bytes + /// + /// https://developer.android.com/reference/android/os/StatFs#getTotalBytes() + final int totalDiskSize; + + /// Describes what features are available on the current device. + /// + /// This can be used to check if the device has, for example, a front-facing + /// camera, or a touchscreen. However, in many cases this is not the best + /// API to use. For example, if you are interested in bluetooth, this API + /// can tell you if the device has a bluetooth radio, but it cannot tell you + /// if bluetooth is currently enabled, or if you have been granted the + /// necessary permissions to use it. Please *only* use this if there is no + /// other way to determine if a feature is supported. + /// + /// This data comes from Android's PackageManager.getSystemAvailableFeatures, + /// and many of the common feature strings to look for are available in + /// PackageManager's public documentation: + /// https://developer.android.com/reference/android/content/pm/PackageManager + final List systemFeatures; + + /// `true` if the application is running on a low-RAM device, `false` otherwise. + final bool isLowRamDevice; + + /// Total physical RAM size of the device in megabytes + /// + /// https://developer.android.com/reference/android/app/ActivityManager.MemoryInfo#totalMem + final int physicalRamSize; + + /// Current unallocated RAM size of the device in megabytes + /// + /// https://developer.android.com/reference/android/app/ActivityManager.MemoryInfo#availMem + final int availableRamSize; + + /// Deserializes from the message received from [_kChannel]. + static AndroidDeviceInfo fromMap(Map map) { + return AndroidDeviceInfo._( + data: map, + version: AndroidBuildVersion._fromMap( + map['version']?.cast() ?? {}, + ), + board: map['board'], + bootloader: map['bootloader'], + brand: map['brand'], + device: map['device'], + display: map['display'], + fingerprint: map['fingerprint'], + hardware: map['hardware'], + host: map['host'], + id: map['id'], + manufacturer: map['manufacturer'], + model: map['model'], + product: map['product'], + name: map['name'] ?? '', + supported32BitAbis: _fromList(map['supported32BitAbis'] ?? []), + supported64BitAbis: _fromList(map['supported64BitAbis'] ?? []), + supportedAbis: _fromList(map['supportedAbis'] ?? []), + tags: map['tags'], + type: map['type'], + isPhysicalDevice: map['isPhysicalDevice'], + freeDiskSize: map['freeDiskSize'], + totalDiskSize: map['totalDiskSize'], + systemFeatures: _fromList(map['systemFeatures'] ?? []), + isLowRamDevice: map['isLowRamDevice'], + physicalRamSize: map['physicalRamSize'], + availableRamSize: map['availableRamSize'], + ); + } + + /// Initializes the application metadata with mock values for testing. + @visibleForTesting + static AndroidDeviceInfo setMockInitialValues({ + required AndroidBuildVersion version, + required String board, + required String bootloader, + required String brand, + required String device, + required String display, + required String fingerprint, + required String hardware, + required String host, + required String id, + required String manufacturer, + required String model, + required String product, + required String name, + required List supported32BitAbis, + required List supported64BitAbis, + required List supportedAbis, + required String tags, + required String type, + required bool isPhysicalDevice, + required int freeDiskSize, + required int totalDiskSize, + required List systemFeatures, + required bool isLowRamDevice, + required int physicalRamSize, + required int availableRamSize, + }) { + final Map data = { + 'version': { + 'baseOS': version.baseOS, + 'sdkInt': version.sdkInt, + 'release': version.release, + 'codename': version.codename, + 'incremental': version.incremental, + 'previewSdkInt': version.previewSdkInt, + 'securityPatch': version.securityPatch, + }, + 'board': board, + 'bootloader': bootloader, + 'brand': brand, + 'device': device, + 'display': display, + 'fingerprint': fingerprint, + 'hardware': hardware, + 'host': host, + 'id': id, + 'manufacturer': manufacturer, + 'model': model, + 'product': product, + 'name': name, + 'supported32BitAbis': supported32BitAbis, + 'supported64BitAbis': supported64BitAbis, + 'supportedAbis': supportedAbis, + 'tags': tags, + 'type': type, + 'isPhysicalDevice': isPhysicalDevice, + 'freeDiskSize': freeDiskSize, + 'totalDiskSize': totalDiskSize, + 'systemFeatures': systemFeatures, + 'isLowRamDevice': isLowRamDevice, + 'physicalRamSize': physicalRamSize, + 'availableRamSize': availableRamSize, + }; + + return AndroidDeviceInfo._( + data: data, + version: version, + board: board, + bootloader: bootloader, + brand: brand, + device: device, + display: display, + fingerprint: fingerprint, + hardware: hardware, + host: host, + id: id, + manufacturer: manufacturer, + model: model, + product: product, + name: name, + supported32BitAbis: _fromList(supported32BitAbis), + supported64BitAbis: _fromList(supported64BitAbis), + supportedAbis: _fromList(supportedAbis), + tags: tags, + type: type, + isPhysicalDevice: isPhysicalDevice, + freeDiskSize: freeDiskSize, + totalDiskSize: totalDiskSize, + systemFeatures: _fromList(systemFeatures), + isLowRamDevice: isLowRamDevice, + physicalRamSize: physicalRamSize, + availableRamSize: availableRamSize, + ); + } + + /// Deserializes message as `List` + static List _fromList(List message) { + final list = message.takeWhile((item) => item != null).toList(); + return List.from(list); + } +} + +/// Version values of the current Android operating system build derived from +/// `android.os.Build.VERSION`. +/// +/// See: https://developer.android.com/reference/android/os/Build.VERSION.html +class AndroidBuildVersion { + const AndroidBuildVersion._({ + this.baseOS, + required this.codename, + required this.incremental, + required this.previewSdkInt, + required this.release, + required this.sdkInt, + this.securityPatch, + }); + + /// The base OS build the product is based on. + /// Available only on Android M (API 23) and newer + final String? baseOS; + + /// The current development codename, or the string "REL" if this is a release build. + final String codename; + + /// The internal value used by the underlying source control to represent this build. + /// Available only on Android M (API 23) and newer + final String incremental; + + /// The developer preview revision of a pre-release SDK. + final int? previewSdkInt; + + /// The user-visible version string. + final String release; + + /// The user-visible SDK version of the framework. + /// + /// Possible values are defined in: https://developer.android.com/reference/android/os/Build.VERSION_CODES.html + final int sdkInt; + + /// The user-visible security patch level. + /// Available only on Android M (API 23) and newer + final String? securityPatch; + + /// Serializes [ AndroidBuildVersion ] to map. + @Deprecated('[toMap] method will be discontinued') + Map toMap() { + return { + 'baseOS': baseOS, + 'sdkInt': sdkInt, + 'release': release, + 'codename': codename, + 'incremental': incremental, + 'previewSdkInt': previewSdkInt, + 'securityPatch': securityPatch, + }; + } + + /// Deserializes from the map message received from [_kChannel]. + static AndroidBuildVersion _fromMap(Map map) { + return AndroidBuildVersion._( + baseOS: map['baseOS'], + codename: map['codename'], + incremental: map['incremental'], + previewSdkInt: map['previewSdkInt'], + release: map['release'], + sdkInt: map['sdkInt'], + securityPatch: map['securityPatch'], + ); + } + + /// Initializes the application metadata with mock values for testing. + @visibleForTesting + static AndroidBuildVersion setMockInitialValues({ + String? baseOS, + required String codename, + required String incremental, + required int previewSdkInt, + required String release, + required int sdkInt, + String? securityPatch, + }) { + return AndroidBuildVersion._( + baseOS: baseOS, + codename: codename, + incremental: incremental, + previewSdkInt: previewSdkInt, + release: release, + sdkInt: sdkInt, + securityPatch: securityPatch, + ); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/ios_device_info.dart b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/ios_device_info.dart new file mode 100644 index 00000000..def717e9 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/ios_device_info.dart @@ -0,0 +1,222 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:device_info_plus_platform_interface/model/base_device_info.dart'; +import 'package:meta/meta.dart'; + +/// Information derived from `UIDevice`. +/// +/// See: https://developer.apple.com/documentation/uikit/uidevice +class IosDeviceInfo extends BaseDeviceInfo { + /// IOS device info class. + IosDeviceInfo._({ + required Map data, + required this.name, + required this.systemName, + required this.systemVersion, + required this.model, + required this.modelName, + required this.localizedModel, + required this.freeDiskSize, + required this.totalDiskSize, + this.identifierForVendor, + required this.isPhysicalDevice, + required this.physicalRamSize, + required this.availableRamSize, + required this.isiOSAppOnMac, + required this.utsname, + }) : super(data); + + /// Device name. + /// + /// On iOS < 16 returns user-assigned device name + /// On iOS >= 16 returns a generic device name if project has + /// no entitlement to get user-assigned device name. + /// https://developer.apple.com/documentation/uikit/uidevice/1620015-name + final String name; + + /// The name of the current operating system. + /// https://developer.apple.com/documentation/uikit/uidevice/1620054-systemname + final String systemName; + + /// The current operating system version. + /// https://developer.apple.com/documentation/uikit/uidevice/1620043-systemversion + final String systemVersion; + + /// Device model according to OS + /// https://developer.apple.com/documentation/uikit/uidevice/1620044-model + final String model; + + /// Commercial or user-known model name + /// Examples: `iPhone 16 Pro`, `iPad Pro 11-Inch 3` + final String modelName; + + /// Localized name of the device model. + /// https://developer.apple.com/documentation/uikit/uidevice/1620029-localizedmodel + final String localizedModel; + + /// Unique UUID value identifying the current device. + /// https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor + final String? identifierForVendor; + + /// `false` if the application is running in a simulator, `true` otherwise. + final bool isPhysicalDevice; + + /// Total physical RAM size of the device in megabytes + final int physicalRamSize; + + /// Current unallocated RAM size of the device in megabytes + final int availableRamSize; + + /// that indicates whether the process is an iPhone or iPad app running on a Mac. + /// https://developer.apple.com/documentation/foundation/nsprocessinfo/3608556-iosapponmac + final bool isiOSAppOnMac; + + /// Operating system information derived from `sys/utsname.h`. + final IosUtsname utsname; + + /// Free disk size in bytes + final int freeDiskSize; + + /// Total disk size in bytes + final int totalDiskSize; + + /// Deserializes from the map message received from [_kChannel]. + static IosDeviceInfo fromMap(Map map) { + return IosDeviceInfo._( + data: map, + name: map['name'], + systemName: map['systemName'], + systemVersion: map['systemVersion'], + model: map['model'], + modelName: map['modelName'], + localizedModel: map['localizedModel'], + identifierForVendor: map['identifierForVendor'], + freeDiskSize: map['freeDiskSize'], + totalDiskSize: map['totalDiskSize'], + isPhysicalDevice: map['isPhysicalDevice'], + physicalRamSize: map['physicalRamSize'], + availableRamSize: map['availableRamSize'], + isiOSAppOnMac: map['isiOSAppOnMac'], + utsname: IosUtsname._fromMap( + map['utsname']?.cast() ?? {}, + ), + ); + } + + /// Initializes the application metadata with mock values for testing. + @visibleForTesting + static IosDeviceInfo setMockInitialValues({ + required String name, + required String systemName, + required String systemVersion, + required String model, + required String modelName, + required String localizedModel, + required int freeDiskSize, + required int totalDiskSize, + String? identifierForVendor, + required bool isPhysicalDevice, + required bool isiOSAppOnMac, + required int physicalRamSize, + required int availableRamSize, + required IosUtsname utsname, + }) { + final Map data = { + 'name': name, + 'systemName': systemName, + 'systemVersion': systemVersion, + 'model': model, + 'modelName': modelName, + 'localizedModel': localizedModel, + 'identifierForVendor': identifierForVendor, + 'freeDiskSize': freeDiskSize, + 'totalDiskSize': totalDiskSize, + 'isPhysicalDevice': isPhysicalDevice, + 'isiOSAppOnMac': isiOSAppOnMac, + 'physicalRamSize': physicalRamSize, + 'availableRamSize': availableRamSize, + 'utsname': { + 'sysname': utsname.sysname, + 'nodename': utsname.nodename, + 'release': utsname.release, + 'version': utsname.version, + 'machine': utsname.machine, + }, + }; + return IosDeviceInfo._( + data: data, + name: name, + systemName: systemName, + systemVersion: systemVersion, + model: model, + modelName: modelName, + localizedModel: localizedModel, + identifierForVendor: identifierForVendor, + freeDiskSize: freeDiskSize, + totalDiskSize: totalDiskSize, + isPhysicalDevice: isPhysicalDevice, + isiOSAppOnMac: isiOSAppOnMac, + physicalRamSize: physicalRamSize, + availableRamSize: availableRamSize, + utsname: utsname, + ); + } +} + +/// Information derived from `utsname`. +/// See http://pubs.opengroup.org/onlinepubs/7908799/xsh/sysutsname.h.html for details. +class IosUtsname { + const IosUtsname._({ + required this.sysname, + required this.nodename, + required this.release, + required this.version, + required this.machine, + }); + + /// Operating system name. + final String sysname; + + /// Network node name. + final String nodename; + + /// Release level. + final String release; + + /// Version level. + final String version; + + /// Hardware type (e.g. 'iPhone7,1' for iPhone 6 Plus). + final String machine; + + /// Deserializes from the map message received from [_kChannel]. + static IosUtsname _fromMap(Map map) { + return IosUtsname._( + sysname: map['sysname'], + nodename: map['nodename'], + release: map['release'], + version: map['version'], + machine: map['machine'], + ); + } + + /// Initializes the application metadata with mock values for testing. + @visibleForTesting + static IosUtsname setMockInitialValues({ + required String sysname, + required String nodename, + required String release, + required String version, + required String machine, + }) { + return IosUtsname._( + sysname: sysname, + nodename: nodename, + release: release, + version: version, + machine: machine, + ); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/linux_device_info.dart b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/linux_device_info.dart new file mode 100644 index 00000000..f7aa1088 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/linux_device_info.dart @@ -0,0 +1,168 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:device_info_plus_platform_interface/model/base_device_info.dart'; + +/// Device information for a Linux system. +/// +/// See: +/// - https://www.freedesktop.org/software/systemd/man/os-release.html +/// - https://www.freedesktop.org/software/systemd/man/machine-id.html +class LinuxDeviceInfo implements BaseDeviceInfo { + /// Constructs a LinuxDeviceInfo. + LinuxDeviceInfo({ + required this.name, + this.version, + required this.id, + this.idLike, + this.versionCodename, + this.versionId, + required this.prettyName, + this.buildId, + this.variant, + this.variantId, + required this.machineId, + }); + + /// A string identifying the operating system, without a version component, + /// and suitable for presentation to the user. + /// + /// Examples: 'Fedora', 'Debian GNU/Linux'. + /// + /// If not set, defaults to 'Linux'. + final String name; + + /// A string identifying the operating system version, excluding any OS name + /// information, possibly including a release code name, and suitable for + /// presentation to the user. + /// + /// Examples: '17', '17 (Beefy Miracle)'. + /// + /// This field is optional and may be null on some systems. + final String? version; + + /// A lower-case string identifying the operating system, excluding any + /// version information and suitable for processing by scripts or usage in + /// generated filenames. + /// + /// The ID contains no spaces or other characters outside of 0–9, a–z, '.', + /// '_' and '-'. + /// + /// Examples: 'fedora', 'debian'. + /// + /// If not set, defaults to 'linux'. + final String id; + + /// A space-separated list of operating system identifiers in the same syntax + /// as the [id] value. It lists identifiers of operating systems that are + /// closely related to the local operating system in regards to packaging + /// and programming interfaces, for example listing one or more OS identifiers + /// the local OS is a derivative from. + /// + /// Examples: an operating system with [id] 'centos', would list 'rhel' and + /// 'fedora', and an operating system with [id] 'ubuntu' would list 'debian'. + /// + /// This field is optional and may be null on some systems. + final List? idLike; + + /// A lower-case string identifying the operating system release code name, + /// excluding any OS name information or release version, and suitable for + /// processing by scripts or usage in generated filenames. + /// + /// The codename contains no spaces or other characters outside of 0–9, a–z, + /// '.', '_' and '-'. + /// + /// Examples: 'buster', 'xenial'. + /// + /// This field is optional and may be null on some systems. + final String? versionCodename; + + /// A lower-case string identifying the operating system version, excluding + /// any OS name information or release code name, and suitable for processing + /// by scripts or usage in generated filenames. + /// + /// The version is mostly numeric, and contains no spaces or other characters + /// outside of 0–9, a–z, '.', '_' and '-'. + /// + /// Examples: '17', '11.04'. + /// + /// This field is optional and may be null on some systems. + final String? versionId; + + /// A pretty operating system name in a format suitable for presentation to + /// the user. May or may not contain a release code name or OS version of some + /// kind, as suitable. + /// + /// Examples: 'Fedora 17 (Beefy Miracle)'. + /// + /// If not set, defaults to 'Linux'. + final String prettyName; + + /// A string uniquely identifying the system image used as the origin for a + /// distribution (it is not updated with system updates). The field can be + /// identical between different [versionId]s as `buildId` is an only a unique + /// identifier to a specific version. + /// + /// Examples: '2013-03-20.3', '201303203'. + /// + /// This field is optional and may be null on some systems. + final String? buildId; + + /// A string identifying a specific variant or edition of the operating system + /// suitable for presentation to the user. This field may be used to inform + /// the user that the configuration of this system is subject to a specific + /// divergent set of rules or default configuration settings. + /// + /// Examples: 'Server Edition', 'Smart Refrigerator Edition'. + /// + /// Note: this field is for display purposes only. The [variantId] field + /// should be used for making programmatic decisions. + /// + /// This field is optional and may be null on some systems. + final String? variant; + + /// A lower-case string identifying a specific variant or edition of the + /// operating system. This may be interpreted in order to determine a + /// divergent default configuration. + /// + /// The variant ID contains no spaces or other characters outside of 0–9, a–z, + /// '.', '_' and '-'. + /// + /// Examples: 'server', 'embedded'. + /// + /// This field is optional and may be null on some systems. + final String? variantId; + + /// A unique machine ID of the local system that is set during installation or + /// boot. The machine ID is hexadecimal, 32-character, lowercase ID. When + /// decoded from hexadecimal, this corresponds to a 16-byte/128-bit value. + final String? machineId; + + @override + // ignore: deprecated_member_use_from_same_package + Map get data => toMap(); + + @Deprecated('Use [data] getter instead') + @override + Map toMap() { + return { + 'name': name, + 'version': version, + 'id': id, + 'idLike': idLike, + 'versionCodename': versionCodename, + 'versionId': versionId, + 'prettyName': prettyName, + 'buildId': buildId, + 'variant': variant, + 'variantId': variantId, + 'machineId': machineId, + }; + } + + @override + String toString() { + return 'LinuxDeviceInfo(name: $name, version: $version, id: $id, idLike: $idLike, versionCodename: $versionCodename, versionId: $versionId, prettyName: $prettyName, buildId: $buildId, variant: $variant, variantId: $variantId, machineId: $machineId)'; + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/macos_device_info.dart b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/macos_device_info.dart new file mode 100644 index 00000000..e1812cbc --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/macos_device_info.dart @@ -0,0 +1,151 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:device_info_plus_platform_interface/model/base_device_info.dart'; +import 'package:meta/meta.dart'; + +/// Object encapsulating MACOS device information. +class MacOsDeviceInfo extends BaseDeviceInfo { + /// Constructs a MacOsDeviceInfo. + MacOsDeviceInfo._({ + required Map data, + required this.computerName, + required this.hostName, + required this.arch, + required this.model, + required this.modelName, + required this.kernelVersion, + required this.osRelease, + required this.majorVersion, + required this.minorVersion, + required this.patchVersion, + required this.activeCPUs, + required this.memorySize, + required this.cpuFrequency, + required this.systemGUID, + }) : super(data); + + /// Name given to the local machine. + final String computerName; + + /// Operating system type + final String hostName; + + /// Machine cpu architecture + /// Note, that on Apple Silicon Macs can return `x86_64` if app runs via Rosetta + final String arch; + + /// Device model identifier + /// Examples: `MacBookPro18,3`, `Mac16,2`. + final String model; + + /// Device model name + /// Examples: `MacBook Pro (16-inch, 2021)`, `iMac (24-inch, 2024)`. + final String modelName; + + /// Machine Kernel version. + /// Examples: + /// `Darwin Kernel Version 15.3.0: Thu Dec 10 18:40:58 PST 2015; root:xnu-3248.30.4~1/RELEASE_X86_64` + /// or + /// `Darwin Kernel Version 15.0.0: Wed Dec 9 22:19:38 PST 2015; root:xnu-3248.31.3~2/RELEASE_ARM64_S8000` + final String kernelVersion; + + /// Operating system release number + final String osRelease; + + /// The major release number, such as 10 in version 10.9.3. + final int majorVersion; + + /// The minor release number, such as 9 in version 10.9.3. + final int minorVersion; + + /// The update release number, such as 3 in version 10.9.3. + final int patchVersion; + + /// Number of active CPUs + final int activeCPUs; + + /// Machine's memory size + final int memorySize; + + /// Device CPU Frequency + final int cpuFrequency; + + /// Device GUID + final String? systemGUID; + + /// Constructs a [MacOsDeviceInfo] from a Map of dynamic. + static MacOsDeviceInfo fromMap(Map map) { + return MacOsDeviceInfo._( + data: map, + computerName: map['computerName'], + hostName: map['hostName'], + arch: map['arch'], + model: map['model'], + modelName: map['modelName'], + kernelVersion: map['kernelVersion'], + osRelease: map['osRelease'], + majorVersion: map['majorVersion'], + minorVersion: map['minorVersion'], + patchVersion: map['patchVersion'], + activeCPUs: map['activeCPUs'], + memorySize: map['memorySize'], + cpuFrequency: map['cpuFrequency'], + systemGUID: map['systemGUID'], + ); + } + + /// Initializes the application metadata with mock values for testing. + @visibleForTesting + static MacOsDeviceInfo setMockInitialValues({ + required String computerName, + required String hostName, + required String arch, + required String model, + required String modelName, + required String kernelVersion, + required String osRelease, + required int majorVersion, + required int minorVersion, + required int patchVersion, + required int activeCPUs, + required int memorySize, + required int cpuFrequency, + required String systemGUID, + }) { + final Map data = { + 'computerName': computerName, + 'hostName': hostName, + 'arch': arch, + 'model': model, + 'modelName': modelName, + 'kernelVersion': kernelVersion, + 'osRelease': osRelease, + 'majorVersion': majorVersion, + 'minorVersion': minorVersion, + 'patchVersion': patchVersion, + 'activeCPUs': activeCPUs, + 'memorySize': memorySize, + 'cpuFrequency': cpuFrequency, + 'systemGUID': systemGUID, + }; + return MacOsDeviceInfo._( + data: data, + computerName: computerName, + hostName: hostName, + arch: arch, + model: model, + modelName: modelName, + kernelVersion: kernelVersion, + osRelease: osRelease, + majorVersion: majorVersion, + minorVersion: minorVersion, + patchVersion: patchVersion, + activeCPUs: activeCPUs, + memorySize: memorySize, + cpuFrequency: cpuFrequency, + systemGUID: systemGUID, + ); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/web_browser_info.dart b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/web_browser_info.dart new file mode 100644 index 00000000..03fa7f83 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/web_browser_info.dart @@ -0,0 +1,188 @@ +// Copyright 2020 The Flutter Community Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:device_info_plus_platform_interface/model/base_device_info.dart'; + +/// List of supported browsers +enum BrowserName { + /// Mozilla Firefox + firefox, + + /// Samsumg Internet Browser + samsungInternet, + + /// Opera Web Browser + opera, + + /// Microsoft Internet Explorer + msie, + + /// Microsoft Edge + edge, + + /// Google Chrome + chrome, + + /// Apple Safari + safari, + + /// Unknown web browser + unknown, +} + +/// Information derived from `navigator`. +/// +/// See: https://developer.mozilla.org/en-US/docs/Web/API/Window/navigator +class WebBrowserInfo implements BaseDeviceInfo { + /// Web Browser info class. + WebBrowserInfo({ + required this.appCodeName, + required this.appName, + required this.appVersion, + required this.deviceMemory, + required this.language, + required this.languages, + required this.platform, + required this.product, + required this.productSub, + required this.userAgent, + required this.vendor, + required this.vendorSub, + required this.maxTouchPoints, + required this.hardwareConcurrency, + }); + + /// the name of the current browser. + BrowserName get browserName { + return _parseUserAgentToBrowserName(); + } + + /// the internal "code" name of the current browser. + /// Note: Do not rely on this property to return the correct value. + final String? appCodeName; + + /// a DOMString with the official name of the browser. + /// Note: Do not rely on this property to return the correct value. + final String? appName; + + /// the version of the browser as a DOMString. + /// Note: Do not rely on this property to return the correct value. + final String? appVersion; + + /// the amount of device memory in gigabytes. This value is an approximation given by rounding to the nearest power of 2 and dividing that number by 1024. + final double? deviceMemory; + + /// a DOMString representing the preferred language of the user, usually the language of the browser UI. The null value is returned when this is unknown. + final String? language; + + /// an array of DOMString representing the languages known to the user, by order of preference. + final List? languages; + + /// the version of the browser as a DOMString. + /// Note: Do not rely on this property to return the correct value. + final String? platform; + + /// Always returns 'Gecko', on any browser. + /// Note: Do not rely on this property to return the correct value. + /// This property is kept only for compatibility purpose. + final String? product; + + /// the build number of the current browser + /// Note: Do not rely on this property to return the correct value. + final String? productSub; + + /// the build number of the current browser (e.g., "20060909") + final String? userAgent; + + /// the vendor name of the current browser + final String? vendor; + + /// Returns the vendor version number (e.g. "6.1") + /// Note: Do not rely on this property to return the correct value. + final String? vendorSub; + + /// the number of logical processor cores available. + final int? hardwareConcurrency; + + /// the maximum number of simultaneous touch contact points are supported by the current device. + final int? maxTouchPoints; + + /// Deserializes from the map message received from [Navigator]. + static WebBrowserInfo fromMap(Map map) { + return WebBrowserInfo( + appCodeName: map['appCodeName'], + appName: map['appName'], + appVersion: map['appVersion'], + deviceMemory: map['deviceMemory'], + language: map['language'], + languages: map['languages'], + platform: map['platform'], + product: map['product'], + productSub: map['productSub'], + userAgent: map['userAgent'], + vendor: map['vendor'], + vendorSub: map['vendorSub'], + hardwareConcurrency: map['hardwareConcurrency'], + maxTouchPoints: map['maxTouchPoints'], + ); + } + + @Deprecated('use [data] instead') + @override + Map toMap() { + return { + 'browserName': browserName, + 'appCodeName': appCodeName, + 'appName': appName, + 'appVersion': appVersion, + 'deviceMemory': deviceMemory, + 'language': language, + 'languages': languages, + 'platform': platform, + 'product': product, + 'productSub': productSub, + 'userAgent': userAgent, + 'vendor': vendor, + 'vendorSub': vendorSub, + 'hardwareConcurrency': hardwareConcurrency, + 'maxTouchPoints': maxTouchPoints, + }; + } + + BrowserName _parseUserAgentToBrowserName() { + final userAgent = this.userAgent; + if (userAgent == null) { + return BrowserName.unknown; + } else if (userAgent.contains('Firefox')) { + return BrowserName.firefox; + // "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0" + } else if (userAgent.contains('SamsungBrowser')) { + return BrowserName.samsungInternet; + // "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G955F Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.4 Chrome/67.0.3396.87 Mobile Safari/537.36 + } else if (userAgent.contains('Opera') || userAgent.contains('OPR')) { + return BrowserName.opera; + // "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 OPR/57.0.3098.106" + } else if (userAgent.contains('Trident')) { + return BrowserName.msie; + // "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; Zoom 3.6.0; wbx 1.0.0; rv:11.0) like Gecko" + } else if (userAgent.contains('Edg')) { + return BrowserName.edge; + // https://docs.microsoft.com/en-us/microsoft-edge/web-platform/user-agent-string + // "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.74 Safari/537.36 Edg/79.0.309.43" + // "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299" + } else if (userAgent.contains('Chrome')) { + return BrowserName.chrome; + // "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/66.0.3359.181 Chrome/66.0.3359.181 Safari/537.36" + } else if (userAgent.contains('Safari')) { + return BrowserName.safari; + // "Mozilla/5.0 (iPhone; CPU iPhone OS 11_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1 980x1306" + } else { + return BrowserName.unknown; + } + } + + @override + // ignore: deprecated_member_use_from_same_package + Map get data => toMap(); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/windows_device_info.dart b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/windows_device_info.dart new file mode 100644 index 00000000..d18037b7 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/lib/src/model/windows_device_info.dart @@ -0,0 +1,184 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:typed_data'; + +import 'package:device_info_plus_platform_interface/model/base_device_info.dart'; + +/// Object encapsulating WINDOWS device information. +class WindowsDeviceInfo implements BaseDeviceInfo { + /// Constructs a [WindowsDeviceInfo]. + const WindowsDeviceInfo({ + required this.computerName, + required this.numberOfCores, + required this.systemMemoryInMegabytes, + required this.userName, + required this.majorVersion, + required this.minorVersion, + required this.buildNumber, + required this.platformId, + required this.csdVersion, + required this.servicePackMajor, + required this.servicePackMinor, + required this.suitMask, + required this.productType, + required this.reserved, + required this.buildLab, + required this.buildLabEx, + required this.digitalProductId, + required this.displayVersion, + required this.editionId, + required this.installDate, + required this.productId, + required this.productName, + required this.registeredOwner, + required this.releaseId, + required this.deviceId, + }); + + /// The computer's fully-qualified DNS name, where available. + final String computerName; + + /// Number of CPU cores on the local machine + final int numberOfCores; + + /// The physically installed memory in the computer. + /// This may not be the same as available memory. + final int systemMemoryInMegabytes; + + final String userName; + + /// The major version number of the operating system. + /// For example, for Windows 2000, the major version number is five. + /// For more information, see the table in Remarks. + /// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw#remarks + final int majorVersion; + + /// The minor version number of the operating system. + /// For example, for Windows 2000, the minor version number is zero. + /// For more information, see the table in Remarks. + /// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw#remarks + final int minorVersion; + + /// The build number of the operating system. + /// For example: + /// - `22000` or greater for Windows 11. + /// - `10240` or greator for Windows 10. + final int buildNumber; + + /// The operating system platform. For Win32 on NT-based operating systems, + /// RtlGetVersion returns the value `VER_PLATFORM_WIN32_NT`. + final int platformId; + + /// The service-pack version string. + /// + /// This member contains a string, such as "Service Pack 3", which indicates + /// the latest service pack installed on the system. + final String csdVersion; + + /// The major version number of the latest service pack installed on the system. + /// For example, for Service Pack 3, the major version number is three. If no + /// service pack has been installed, the value is zero. + final int servicePackMajor; + + /// The minor version number of the latest service pack installed on the + /// system. For example, for Service Pack 3, the minor version number is zero. + final int servicePackMinor; + + /// The product suites available on the system. + final int suitMask; + + /// The product type. This member contains additional information about the + /// system. + final int productType; + + /// Reserved for future use. + final int reserved; + + /// Value of `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows + /// NT\CurrentVersion\BuildLab` registry key. For example: + /// `22000.co_release.210604-1628`. + final String buildLab; + + /// Value of `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows + /// NT\CurrentVersion\BuildLabEx` registry key. For example: + /// `22000.1.amd64fre.co_release.210604-1628`. + final String buildLabEx; + + /// Value of `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows + /// NT\CurrentVersion\DigitalProductId` registry key. + final Uint8List digitalProductId; + + /// Value of `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows + /// NT\CurrentVersion\DisplayVersion` registry key. For example: `21H2`. + final String displayVersion; + + /// Value of `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows + /// NT\CurrentVersion\EditionID` registry key. + final String editionId; + + /// Value of `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows + /// NT\CurrentVersion\InstallDate` registry key. + final DateTime installDate; + + /// Displayed as "Product ID" in Windows Settings. Value of the + /// `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows + /// NT\CurrentVersion\ProductId` registry key. For example: + /// `00000-00000-0000-AAAAA`. + final String productId; + + /// Value of `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows + /// NT\CurrentVersion\ProductName` registry key. For example: `Windows 10 Home + /// Single Language`. + final String productName; + + /// Value of the `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows + /// NT\CurrentVersion\RegisteredOwner` registry key. For example: `Microsoft + /// Corporation`. + final String registeredOwner; + + /// Value of the `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows + /// NT\CurrentVersion\ReleaseId` registry key. For example: `1903`. + final String releaseId; + + /// Displayed as "Device ID" in Windows Settings. Value of + /// `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SQMClient\MachineId` registry key. + final String deviceId; + + @Deprecated('use [data] instead') + @override + Map toMap() { + return { + 'computerName': computerName, + 'numberOfCores': numberOfCores, + 'systemMemoryInMegabytes': systemMemoryInMegabytes, + 'userName': userName, + 'majorVersion': majorVersion, + 'minorVersion': minorVersion, + 'buildNumber': buildNumber, + 'platformId': platformId, + 'csdVersion': csdVersion, + 'servicePackMajor': servicePackMajor, + 'servicePackMinor': servicePackMinor, + 'suitMask': suitMask, + 'productType': productType, + 'reserved': reserved, + 'buildLab': buildLab, + 'buildLabEx': buildLabEx, + 'digitalProductId': digitalProductId, + 'displayVersion': displayVersion, + 'editionId': editionId, + 'installDate': installDate, + 'productId': productId, + 'productName': productName, + 'registeredOwner': registeredOwner, + 'releaseId': releaseId, + 'deviceId': deviceId, + }; + } + + @override + // ignore: deprecated_member_use_from_same_package + Map get data => toMap(); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus.podspec b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus.podspec new file mode 100644 index 00000000..a5031bea --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus.podspec @@ -0,0 +1,23 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'device_info_plus' + s.version = '0.0.1' + s.summary = 'No-op implementation of the macos device_info_plus to avoid build issues on macos' + s.description = <<-DESC + No-op implementation of the device_info_plus plugin to avoid build issues on macos. +https://github.com/flutter/flutter/issues/46618 + DESC + s.homepage = 'https://github.com/fluttercommunity/plus_plugins/tree/master/packages/device_info_plus' + s.license = { :file => '../LICENSE' } + s.author = { 'Flutter Community' => 'authors@fluttercommunity.dev' } + s.source = { :path => '.' } + s.source_files = 'device_info_plus/Sources/device_info_plus/**/*.swift' + s.public_header_files = 'device_info_plus/Sources/device_info_plus/**/*.h' + s.dependency 'FlutterMacOS' + + s.platform = :osx + s.osx.deployment_target = '10.14' + s.resource_bundles = {'device_info_plus_privacy' => ['device_info_plus/Sources/device_info_plus/PrivacyInfo.xcprivacy']} +end diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Package.swift b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Package.swift new file mode 100644 index 00000000..9cd83e6e --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Package.swift @@ -0,0 +1,24 @@ +// swift-tools-version: 5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "device_info_plus", + platforms: [ + .macOS("10.14") + ], + products: [ + .library(name: "device-info-plus", targets: ["device_info_plus"]) + ], + dependencies: [], + targets: [ + .target( + name: "device_info_plus", + dependencies: [], + resources: [ + .process("PrivacyInfo.xcprivacy"), + ] + ) + ] +) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Sources/device_info_plus/CwlSysctl.swift b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Sources/device_info_plus/CwlSysctl.swift new file mode 100644 index 00000000..3f29e31c --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Sources/device_info_plus/CwlSysctl.swift @@ -0,0 +1,152 @@ +// +// CwlSysctl.swift +// CwlUtils +// +// Created by Matt Gallagher on 2016/02/03. +// Copyright © 2016 Matt Gallagher ( https://www.cocoawithlove.com ). All rights reserved. +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +// IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +import Foundation + +/// A "static"-only namespace around a series of functions that operate on buffers returned from the `Darwin.sysctl` function +public struct Sysctl { + /// Possible errors. + public enum Error: Swift.Error { + case unknown + case malformedUTF8 + case invalidSize + case posixError(POSIXErrorCode) + } + + /// Access the raw data for an array of sysctl identifiers. + public static func data(for keys: [Int32]) throws -> [Int8] { + return try keys.withUnsafeBufferPointer() { keysPointer throws -> [Int8] in + // Preflight the request to get the required data size + var requiredSize = 0 + let preFlightResult = Darwin.sysctl(UnsafeMutablePointer(mutating: keysPointer.baseAddress), UInt32(keys.count), nil, &requiredSize, nil, 0) + if preFlightResult != 0 { + throw POSIXErrorCode(rawValue: errno).map { + return Error.posixError($0) + } ?? Error.unknown + } + + // Run the actual request with an appropriately sized array buffer + let data = Array(repeating: 0, count: requiredSize) + let result = data.withUnsafeBufferPointer() { dataBuffer -> Int32 in + return Darwin.sysctl(UnsafeMutablePointer(mutating: keysPointer.baseAddress), UInt32(keys.count), UnsafeMutableRawPointer(mutating: dataBuffer.baseAddress), &requiredSize, nil, 0) + } + if result != 0 { + throw POSIXErrorCode(rawValue: errno).map { Error.posixError($0) } ?? Error.unknown + } + + return data + } + } + + /// Convert a sysctl name string like "hw.memsize" to the array of `sysctl` identifiers (e.g. [CTL_HW, HW_MEMSIZE]) + public static func keys(for name: String) throws -> [Int32] { + var keysBufferSize = Int(CTL_MAXNAME) + var keysBuffer = Array(repeating: 0, count: keysBufferSize) + try keysBuffer.withUnsafeMutableBufferPointer { (lbp: inout UnsafeMutableBufferPointer) throws in + try name.withCString { (nbp: UnsafePointer) throws in + guard sysctlnametomib(nbp, lbp.baseAddress, &keysBufferSize) == 0 else { + throw POSIXErrorCode(rawValue: errno).map { Error.posixError($0) } ?? Error.unknown + } + } + } + if keysBuffer.count > keysBufferSize { + keysBuffer.removeSubrange(keysBufferSize..(ofType: T.Type, forKeys keys: [Int32]) throws -> T { + let buffer = try data(for: keys) + if buffer.count != MemoryLayout.size { + throw Error.invalidSize + } + return try buffer.withUnsafeBufferPointer() { bufferPtr throws -> T in + guard let baseAddress = bufferPtr.baseAddress else { throw Error.unknown } + return baseAddress.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee } + } + } + + /// Invoke `sysctl` with an array of identifers, interpreting the returned buffer as the specified type. This function will throw `Error.invalidSize` if the size of buffer returned from `sysctl` fails to match the size of `T`. + public static func value(ofType type: T.Type, forKeys keys: Int32...) throws -> T { + return try value(ofType: type, forKeys: keys) + } + + /// Invoke `sysctl` with the specified name, interpreting the returned buffer as the specified type. This function will throw `Error.invalidSize` if the size of buffer returned from `sysctl` fails to match the size of `T`. + public static func value(ofType type: T.Type, forName name: String) throws -> T { + return try value(ofType: type, forKeys: keys(for: name)) + } + + /// Invoke `sysctl` with an array of identifers, interpreting the returned buffer as a `String`. This function will throw `Error.malformedUTF8` if the buffer returned from `sysctl` cannot be interpreted as a UTF8 buffer. + public static func string(for keys: [Int32]) throws -> String { + let optionalString = try data(for: keys).withUnsafeBufferPointer() { dataPointer -> String? in + dataPointer.baseAddress.flatMap { String(validatingUTF8: $0) } + } + guard let s = optionalString else { + throw Error.malformedUTF8 + } + return s + } + + /// Invoke `sysctl` with an array of identifers, interpreting the returned buffer as a `String`. This function will throw `Error.malformedUTF8` if the buffer returned from `sysctl` cannot be interpreted as a UTF8 buffer. + public static func string(for keys: Int32...) throws -> String { + return try string(for: keys) + } + + /// Invoke `sysctl` with the specified name, interpreting the returned buffer as a `String`. This function will throw `Error.malformedUTF8` if the buffer returned from `sysctl` cannot be interpreted as a UTF8 buffer. + public static func string(for name: String) throws -> String { + return try string(for: keys(for: name)) + } + + /// e.g. "MyComputer.local" (from System Preferences -> Sharing -> Computer Name) + public static var hostName: String { return (try? Sysctl.string(for: [CTL_KERN, KERN_HOSTNAME])) ?? "" } + + /// e.g. "x86_64" or "arm64" + public static var machine: String { return (try? Sysctl.string(for: [CTL_HW, HW_MACHINE])) ?? "" } + + /// e.g. "MacBookPro18,2" + public static var model: String { return (try? Sysctl.string(for: [CTL_HW, HW_MODEL])) ?? "" } + + /// e.g. "8" or "2" + public static var activeCPUs: Int32 { return (try? Sysctl.value(ofType: Int32.self, forKeys: [CTL_HW, HW_AVAILCPU])) ?? 0 } + + /// e.g. "15.3.0" or "15.0.0" + public static var osRelease: String { return (try? Sysctl.string(for: [CTL_KERN, KERN_OSRELEASE])) ?? "" } + + /// e.g. "Darwin" or "Darwin" + public static var osType: String { return (try? Sysctl.string(for: [CTL_KERN, KERN_OSTYPE])) ?? "" } + + /// e.g. "15D21" or "13D20" + public static var osVersion: String { return (try? Sysctl.string(for: [CTL_KERN, KERN_OSVERSION])) ?? "" } + + /// e.g. "Darwin Kernel Version 15.3.0: Thu Dec 10 18:40:58 PST 2015; root:xnu-3248.30.4~1/RELEASE_X86_64" or + /// "Darwin Kernel Version 15.0.0: Wed Dec 9 22:19:38 PST 2015; root:xnu-3248.31.3~2/RELEASE_ARM64_S8000" + public static var version: String { return (try? Sysctl.string(for: [CTL_KERN, KERN_VERSION])) ?? "" } + + #if os(macOS) + /// e.g. 199506 (not available on iOS) + public static var osRev: Int32 { return (try? Sysctl.value(ofType: Int32.self, forKeys: [CTL_KERN, KERN_OSREV])) ?? 0 } + + /// e.g. 2659000000 (not available on iOS) + public static var cpuFreq: Int64 { return (try? Sysctl.value(ofType: Int64.self, forName: "hw.cpufrequency")) ?? 0 } + + /// e.g. 25769803776 (not available on iOS) + public static var memSize: UInt64 { return (try? Sysctl.value(ofType: UInt64.self, forKeys: [CTL_HW, HW_MEMSIZE])) ?? 0 } + #endif +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Sources/device_info_plus/DeviceIdentifiers.swift b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Sources/device_info_plus/DeviceIdentifiers.swift new file mode 100644 index 00000000..750c9b7f --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Sources/device_info_plus/DeviceIdentifiers.swift @@ -0,0 +1,105 @@ +import Foundation + +// Models list is taken from support.apple.com and https://theapplewiki.com/wiki/Models +// Example of the list with models https://support.apple.com/en-us/102869 + +func getMacModelName(modelNumber: String) -> String { + switch modelNumber { + // MacBook models (2015 and later) + case "MacBook8,1": return "MacBook (12-inch, 2015)" + case "MacBook9,1": return "MacBook (12-inch, 2016)" + case "MacBook10,1": return "MacBook (12-inch, 2017)" + + // MacBook Air models (2013 and later) + case "MacBookAir6,1": return "MacBook Air (11-inch, 2013)" + case "MacBookAir6,2": return "MacBook Air (13-inch, 2013)" + case "MacBookAir7,1": return "MacBook Air (11-inch, 2015)" + case "MacBookAir7,2": return "MacBook Air (13-inch, 2015-2017)" + case "MacBookAir8,1": return "MacBook Air (13-inch, 2018)" + case "MacBookAir8,2": return "MacBook Air (13-inch, 2019)" + case "MacBookAir9,1": return "MacBook Air (13-inch, 2020)" + case "MacBookAir10,1": return "MacBook Air (13-inch, 2020)" + case "Mac14,2": return "MacBook Air (13-inch, 2022)" + case "Mac14,15": return "MacBook Air (15-inch, 2023)" + case "Mac15,12": return "MacBook Air (13-inch, 2024)" + case "Mac15,13": return "MacBook Air (15-inch, 2024)" + case "Mac16,12": return "MacBook Air (13-inch, 2025)" + case "Mac16,13": return "MacBook Air (15-inch, 2025)" + + // MacBook Pro models (2012 and later) + case "MacBookPro10,1": return "MacBook Pro (15-inch, 2012-2013)" + case "MacBookPro10,2": return "MacBook Pro (13-inch, 2012-2013)" + case "MacBookPro11,1": return "MacBook Pro (13-inch, 2013-2014)" + case "MacBookPro11,2", "MacBookPro11,3": return "MacBook Pro (15-inch, 2013-2014)" + case "MacBookPro11,4", "MacBookPro11,5": return "MacBook Pro (15-inch, 2015)" + case "MacBookPro12,1": return "MacBook Pro (13-inch, 2015)" + case "MacBookPro13,1": return "MacBook Pro (13-inch, 2016)" + case "MacBookPro13,2": return "MacBook Pro (13-inch, 2016)" + case "MacBookPro13,3": return "MacBook Pro (15-inch, 2016)" + case "MacBookPro14,1": return "MacBook Pro (13-inch, 2017)" + case "MacBookPro14,2": return "MacBook Pro (13-inch, 2017)" + case "MacBookPro14,3": return "MacBook Pro (15-inch, 2017)" + case "MacBookPro15,1", "MacBookPro15,3": return "MacBook Pro (15-inch, 2018-2019)" + case "MacBookPro15,2": return "MacBook Pro (13-inch, 2018-2019)" + case "MacBookPro15,4": return "MacBook Pro (13-inch, 2019)" + case "MacBookPro16,1", "MacBookPro16,4": return "MacBook Pro (16-inch, 2019)" + case "MacBookPro16,2": return "MacBook Pro (13-inch, 2019)" + case "MacBookPro16,3": return "MacBook Pro (13-inch, 2020)" + case "MacBookPro17,1": return "MacBook Pro (13-inch, 2020)" + case "MacBookPro18,1": return "MacBook Pro (14-inch, 2021)" + case "MacBookPro18,2": return "MacBook Pro (16-inch, 2021)" + case "MacBookPro18,3": return "MacBook Pro (16-inch, 2021)" + case "Mac14,5", "Mac14,9": return "MacBook Pro (14-inch, 2023)" + case "Mac14,6", "Mac14,10": return "MacBook Pro (14-inch, 2023)" + case "Mac14,7": return "MacBook Pro (13-inch, 2022)" + case "Mac15,3": return "MacBook Pro (14-inch, 2023)" + case "Mac15,6", "Mac15,8", "Mac15,10": return "MacBook Pro (14-inch, 2023)" + case "Mac15,7", "Mac15,9", "Mac15,11": return "MacBook Pro (16-inch, 2023)" + case "Mac16,1", "Mac16,6", "Mac16,8": return "MacBook Pro (14-inch, 2024)" + case "Mac16,5", "Mac16,7": return "MacBook Pro (16-inch, 2024)" + case "Mac17,2": return "MacBook Pro (14-inch, 2025)" + + // iMac models (2013 and later) + case "iMac13,1": return "iMac (21.5-inch, 2013)" + case "iMac13,2": return "iMac (27-inch, 2013)" + case "iMac14,1": return "iMac (21.5-inch, 2014)" + case "iMac14,2": return "iMac (27-inch, 2014)" + case "iMac14,4": return "iMac (21.5-inch, 2014)" + case "iMac15,1": return "iMac (27-inch, 2014-2015)" + case "iMac16,1","iMac16,2": return "iMac (21.5-inch, 2015)" + case "iMac17,1": return "iMac (27-inch, 2015)" + case "iMac18,1": return "iMac (21.5-inch, 2017)" + case "iMac18,2": return "iMac (21.5-inch, 2017)" + case "iMac18,3": return "iMac (27-inch, 2017)" + case "iMac19,1": return "iMac (27-inch, 2019)" + case "iMac19,2": return "iMac (21.5-inch, 2019)" + case "iMac20,1", "iMac20,2": return "iMac (27-inch, 2020)" + case "iMac21,1", "iMac21,2": return "iMac (24-inch, 2021)" + case "Mac15,4", "Mac15,5": return "iMac (24-inch, 2023)" + case "Mac16,2", "Mac16,3": return "iMac (24-inch, 2024)" + + // Mac mini models (2012 and later) + case "MacMini6,1", "MacMini6,2": return "Mac mini (2012)" + case "MacMini7,1": return "Mac mini (2014)" + case "MacMini8,1": return "Mac mini (2018)" + case "MacMini9,1": return "Mac mini (2020)" + case "Mac14,12": return "Mac mini (2023)" + case "Mac14,3": return "Mac mini (2023)" + case "Mac16,11", "Mac16,10": return "Mac mini (2024)" + + // Mac Pro models (2013 and later) + case "MacPro6,1": return "Mac Pro (Late 2013)" + case "MacPro7,1": return "Mac Pro (2019)" + case "Mac14,8": return "Mac Pro (2023)" + + // iMac Pro + case "iMacPro1,1": return "iMac Pro (2017)" + + // Mac Studio (2022 and newer) + case "Mac13,1", "Mac13,2": return "Mac Studio (2022)" + case "Mac14,13", "Mac14,14": return "Mac Studio (2023)" + case "Mac15,14", "Mac16,9": return "Mac Studio (2025)" + + default: return "Unknown Model" + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Sources/device_info_plus/DeviceInfoPlusMacosPlugin.swift b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Sources/device_info_plus/DeviceInfoPlusMacosPlugin.swift new file mode 100644 index 00000000..a1f68236 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Sources/device_info_plus/DeviceInfoPlusMacosPlugin.swift @@ -0,0 +1,54 @@ +import Cocoa +import FlutterMacOS + +public class DeviceInfoPlusMacosPlugin: NSObject, FlutterPlugin { + public static func register(with registrar: FlutterPluginRegistrar) { + let channel = FlutterMethodChannel(name: "dev.fluttercommunity.plus/device_info", binaryMessenger: registrar.messenger) + let instance = DeviceInfoPlusMacosPlugin() + registrar.addMethodCallDelegate(instance, channel: channel) + } + + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + switch call.method { + case "getDeviceInfo": + handleDeviceInfo(result: result) + default: + result(FlutterMethodNotImplemented) + } + } + + private func handleDeviceInfo(result: @escaping FlutterResult)-> Void{ + let computerName = Host.current().localizedName ?? Sysctl.hostName + let hostName = Sysctl.osType + let arch = Sysctl.machine + let model = Sysctl.model + let modelName = getMacModelName(modelNumber: Sysctl.model) + let kernelVersion = Sysctl.version + let osRelease = ProcessInfo.processInfo.operatingSystemVersionString + let osVersion = ProcessInfo.processInfo.operatingSystemVersion; + let majorVersion = osVersion.majorVersion + let minorVersion = osVersion.minorVersion + let patchVersion = osVersion.patchVersion + let activeCPUs = Sysctl.activeCPUs + let memorySize = Sysctl.memSize + let cpuFrequency = Sysctl.cpuFreq + let guid = SystemUUID.getSystemUUID() + + result([ + "computerName": computerName, + "hostName": hostName, + "arch": arch, + "model": model, + "modelName": modelName, + "kernelVersion": kernelVersion, + "osRelease": osRelease, + "majorVersion": majorVersion, + "minorVersion": minorVersion, + "patchVersion": patchVersion, + "activeCPUs": activeCPUs, + "memorySize": memorySize, + "cpuFrequency": cpuFrequency, + "systemGUID": guid + ] as [String: Any?]) + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Sources/device_info_plus/PrivacyInfo.xcprivacy b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Sources/device_info_plus/PrivacyInfo.xcprivacy new file mode 100644 index 00000000..918d80be --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Sources/device_info_plus/PrivacyInfo.xcprivacy @@ -0,0 +1,12 @@ + + + + + NSPrivacyTrackingDomains + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + + diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Sources/device_info_plus/SystemUUID.swift b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Sources/device_info_plus/SystemUUID.swift new file mode 100644 index 00000000..a651c5f4 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/macos/device_info_plus/Sources/device_info_plus/SystemUUID.swift @@ -0,0 +1,16 @@ +import Foundation + +public enum SystemUUID { + public static func getSystemUUID() -> String? { + let mainPort: mach_port_t + if #available(macOS 12.0, *) { + mainPort = kIOMainPortDefault + } else { + mainPort = kIOMasterPortDefault + } + let service = IOServiceGetMatchingService(mainPort, IOServiceMatching("IOPlatformExpertDevice")) + let uuid = IORegistryEntryCreateCFProperty(service, kIOPlatformUUIDKey as CFString, kCFAllocatorDefault, 0).takeRetainedValue() as? String + IOObjectRelease(service) + return uuid + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/pubspec.yaml b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/pubspec.yaml new file mode 100644 index 00000000..ad90671e --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/device_info_plus/pubspec.yaml @@ -0,0 +1,53 @@ +name: device_info_plus +description: Flutter plugin providing detailed information about the device + (make, model, etc.), and Android or iOS version the app is running on. +version: 12.3.0 +homepage: https://github.com/fluttercommunity/plus_plugins +repository: https://github.com/fluttercommunity/plus_plugins/tree/main/packages/device_info_plus/device_info_plus +issue_tracker: https://github.com/fluttercommunity/plus_plugins/labels/device_info_plus +topics: + - device + - information + - utils + +flutter: + plugin: + platforms: + android: + package: dev.fluttercommunity.plus.device_info + pluginClass: DeviceInfoPlusPlugin + ios: + pluginClass: FPPDeviceInfoPlusPlugin + linux: + dartPluginClass: DeviceInfoPlusLinuxPlugin + web: + pluginClass: DeviceInfoPlusWebPlugin + fileName: src/device_info_plus_web.dart + macos: + pluginClass: DeviceInfoPlusMacosPlugin + windows: + dartPluginClass: DeviceInfoPlusWindowsPlugin + +dependencies: + device_info_plus_platform_interface: ^7.0.3 + ffi: ^2.1.4 + file: ^7.0.1 + flutter: + sdk: flutter + flutter_web_plugins: + sdk: flutter + meta: ^1.16.0 + web: ^1.1.0 + win32: ^5.11.0 + win32_registry: ^2.1.0 + +dev_dependencies: + flutter_lints: ^5.0.0 + flutter_test: + sdk: flutter + mockito: ^5.4.5 + test: ^1.25.15 + +environment: + sdk: ">=3.7.0 <4.0.0" + flutter: ">=3.29.0" diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/AUTHORS b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/AUTHORS new file mode 100644 index 00000000..557dff97 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/AUTHORS @@ -0,0 +1,6 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/CHANGELOG.md b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/CHANGELOG.md new file mode 100644 index 00000000..54d3a9e6 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/CHANGELOG.md @@ -0,0 +1,76 @@ +## 0.9.4 + +* Adds `getDirectoryPathWithOptions` and `getDirectoryPathsWithOptions` implementations. + +## 0.9.3+3 + +* Updates to Pigeon 26. +* Updates minimum supported SDK version to Flutter 3.32/Dart 3.8. + +## 0.9.3+2 + +* Updates Pigeon to resolve a compilation failure with some versions of glib. + +## 0.9.3+1 + +* Fixes a regression in 0.9.3 with handling of canceled dialogs. + +## 0.9.3 + +* Updates method channel implementation to use Pigeon. +* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. + +## 0.9.2+1 + +* Adds pub topics to package metadata. +* Updates minimum supported SDK version to Flutter 3.7/Dart 2.19. +* Migrates `styleFrom` usage in examples off of deprecated `primary` and `onPrimary` parameters. + +## 0.9.2 + +* Adds `getSaveLocation` and deprecates `getSavePath`. +* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18. + +## 0.9.1+3 + +* Sets a cmake_policy compatibility version to fix build warnings. + +## 0.9.1+2 + +* Clarifies explanation of endorsement in README. +* Aligns Dart and Flutter SDK constraints. + +## 0.9.1+1 + +* Updates links for the merge of flutter/plugins into flutter/packages. +* Updates example code for `use_build_context_synchronously` lint. +* Updates minimum Flutter version to 3.0. + +## 0.9.1 + +* Adds `getDirectoryPaths` implementation. + +## 0.9.0+1 + +* Changes XTypeGroup initialization from final to const. +* Updates minimum Flutter version to 2.10. + +## 0.9.0 + +* Moves source to flutter/plugins. + +## 0.0.3 + +* Adds Dart implementation for in-package method channel. + +## 0.0.2+1 + +* Updates README + +## 0.0.2 + +* Updates SDK constraint to signal compatibility with null safety. + +## 0.0.1 + +* Initial Linux implementation of `file_selector`. diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/get_directory_page.dart b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/get_directory_page.dart new file mode 100644 index 00000000..e483b8c6 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/get_directory_page.dart @@ -0,0 +1,76 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; +import 'package:flutter/material.dart'; + +/// Screen that allows the user to select a directory using `getDirectoryPath`, +/// then displays the selected directory in a dialog. +class GetDirectoryPage extends StatelessWidget { + /// Default Constructor + const GetDirectoryPage({super.key}); + + Future _getDirectoryPath(BuildContext context) async { + const String confirmButtonText = 'Choose'; + final String? directoryPath = await FileSelectorPlatform.instance + .getDirectoryPath(confirmButtonText: confirmButtonText); + if (directoryPath == null) { + // Operation was canceled by the user. + return; + } + if (context.mounted) { + await showDialog( + context: context, + builder: (BuildContext context) => TextDisplay(directoryPath), + ); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Open a text file')), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + ), + child: const Text('Press to ask user to choose a directory'), + onPressed: () => _getDirectoryPath(context), + ), + ], + ), + ), + ); + } +} + +/// Widget that displays a text file in a dialog. +class TextDisplay extends StatelessWidget { + /// Creates a `TextDisplay`. + const TextDisplay(this.directoryPath, {super.key}); + + /// The path selected in the dialog. + final String directoryPath; + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: const Text('Selected Directory'), + content: Scrollbar( + child: SingleChildScrollView(child: Text(directoryPath)), + ), + actions: [ + TextButton( + child: const Text('Close'), + onPressed: () => Navigator.pop(context), + ), + ], + ); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/get_multiple_directories_page.dart b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/get_multiple_directories_page.dart new file mode 100644 index 00000000..fe7fd3d2 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/get_multiple_directories_page.dart @@ -0,0 +1,79 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; +import 'package:flutter/material.dart'; + +/// Screen that allows the user to select one or more directories using `getDirectoryPaths`, +/// then displays the selected directories in a dialog. +class GetMultipleDirectoriesPage extends StatelessWidget { + /// Default Constructor + const GetMultipleDirectoriesPage({super.key}); + + Future _getDirectoryPaths(BuildContext context) async { + const String confirmButtonText = 'Choose'; + final List directoryPaths = await FileSelectorPlatform.instance + .getDirectoryPaths(confirmButtonText: confirmButtonText); + if (directoryPaths.isEmpty) { + // Operation was canceled by the user. + return; + } + if (context.mounted) { + await showDialog( + context: context, + builder: (BuildContext context) => + TextDisplay(directoryPaths.join('\n')), + ); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Select multiple directories')), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + ), + child: const Text( + 'Press to ask user to choose multiple directories', + ), + onPressed: () => _getDirectoryPaths(context), + ), + ], + ), + ), + ); + } +} + +/// Widget that displays a text file in a dialog. +class TextDisplay extends StatelessWidget { + /// Creates a `TextDisplay`. + const TextDisplay(this.directoriesPaths, {super.key}); + + /// The path selected in the dialog. + final String directoriesPaths; + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: const Text('Selected Directories'), + content: Scrollbar( + child: SingleChildScrollView(child: Text(directoriesPaths)), + ), + actions: [ + TextButton( + child: const Text('Close'), + onPressed: () => Navigator.pop(context), + ), + ], + ); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/home_page.dart b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/home_page.dart new file mode 100644 index 00000000..b4988485 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/home_page.dart @@ -0,0 +1,65 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +/// Home Page of the application. +class HomePage extends StatelessWidget { + /// Default Constructor + const HomePage({super.key}); + + @override + Widget build(BuildContext context) { + final ButtonStyle style = ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + ); + return Scaffold( + appBar: AppBar(title: const Text('File Selector Demo Home Page')), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + style: style, + child: const Text('Open a text file'), + onPressed: () => Navigator.pushNamed(context, '/open/text'), + ), + const SizedBox(height: 10), + ElevatedButton( + style: style, + child: const Text('Open an image'), + onPressed: () => Navigator.pushNamed(context, '/open/image'), + ), + const SizedBox(height: 10), + ElevatedButton( + style: style, + child: const Text('Open multiple images'), + onPressed: () => Navigator.pushNamed(context, '/open/images'), + ), + const SizedBox(height: 10), + ElevatedButton( + style: style, + child: const Text('Save a file'), + onPressed: () => Navigator.pushNamed(context, '/save/text'), + ), + const SizedBox(height: 10), + ElevatedButton( + style: style, + child: const Text('Open a get directory dialog'), + onPressed: () => Navigator.pushNamed(context, '/directory'), + ), + const SizedBox(height: 10), + ElevatedButton( + style: style, + child: const Text('Open a get directories dialog'), + onPressed: () => + Navigator.pushNamed(context, '/multi-directories'), + ), + ], + ), + ), + ); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/main.dart b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/main.dart new file mode 100644 index 00000000..28a34200 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/main.dart @@ -0,0 +1,45 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'get_directory_page.dart'; +import 'get_multiple_directories_page.dart'; +import 'home_page.dart'; +import 'open_image_page.dart'; +import 'open_multiple_images_page.dart'; +import 'open_text_page.dart'; +import 'save_text_page.dart'; + +void main() { + runApp(const MyApp()); +} + +/// MyApp is the Main Application. +class MyApp extends StatelessWidget { + /// Default Constructor + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'File Selector Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: const HomePage(), + routes: { + '/open/image': (BuildContext context) => const OpenImagePage(), + '/open/images': (BuildContext context) => + const OpenMultipleImagesPage(), + '/open/text': (BuildContext context) => const OpenTextPage(), + '/save/text': (BuildContext context) => SaveTextPage(), + '/directory': (BuildContext context) => const GetDirectoryPage(), + '/multi-directories': (BuildContext context) => + const GetMultipleDirectoriesPage(), + }, + ); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/open_image_page.dart b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/open_image_page.dart new file mode 100644 index 00000000..f5705d24 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/open_image_page.dart @@ -0,0 +1,91 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io'; + +import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +/// Screen that allows the user to select an image file using +/// `openFiles`, then displays the selected images in a gallery dialog. +class OpenImagePage extends StatelessWidget { + /// Default Constructor + const OpenImagePage({super.key}); + + Future _openImageFile(BuildContext context) async { + const XTypeGroup typeGroup = XTypeGroup( + label: 'images', + extensions: ['jpg', 'png'], + ); + final XFile? file = await FileSelectorPlatform.instance.openFile( + acceptedTypeGroups: [typeGroup], + ); + if (file == null) { + // Operation was canceled by the user. + return; + } + final String fileName = file.name; + final String filePath = file.path; + + if (context.mounted) { + await showDialog( + context: context, + builder: (BuildContext context) => ImageDisplay(fileName, filePath), + ); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Open an image')), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + ), + child: const Text('Press to open an image file(png, jpg)'), + onPressed: () => _openImageFile(context), + ), + ], + ), + ), + ); + } +} + +/// Widget that displays an image in a dialog. +class ImageDisplay extends StatelessWidget { + /// Default Constructor. + const ImageDisplay(this.fileName, this.filePath, {super.key}); + + /// The name of the selected file. + final String fileName; + + /// The path to the selected file. + final String filePath; + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text(fileName), + // On web the filePath is a blob url + // while on other platforms it is a system path. + content: kIsWeb ? Image.network(filePath) : Image.file(File(filePath)), + actions: [ + TextButton( + child: const Text('Close'), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/open_multiple_images_page.dart b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/open_multiple_images_page.dart new file mode 100644 index 00000000..0b9fe352 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/open_multiple_images_page.dart @@ -0,0 +1,101 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io'; + +import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +/// Screen that allows the user to select multiple image files using +/// `openFiles`, then displays the selected images in a gallery dialog. +class OpenMultipleImagesPage extends StatelessWidget { + /// Default Constructor + const OpenMultipleImagesPage({super.key}); + + Future _openImageFile(BuildContext context) async { + const XTypeGroup jpgsTypeGroup = XTypeGroup( + label: 'JPEGs', + extensions: ['jpg', 'jpeg'], + ); + const XTypeGroup pngTypeGroup = XTypeGroup( + label: 'PNGs', + extensions: ['png'], + ); + final List files = await FileSelectorPlatform.instance.openFiles( + acceptedTypeGroups: [jpgsTypeGroup, pngTypeGroup], + ); + if (files.isEmpty) { + // Operation was canceled by the user. + return; + } + if (context.mounted) { + await showDialog( + context: context, + builder: (BuildContext context) => MultipleImagesDisplay(files), + ); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Open multiple images')), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + ), + child: const Text('Press to open multiple images (png, jpg)'), + onPressed: () => _openImageFile(context), + ), + ], + ), + ), + ); + } +} + +/// Widget that displays a text file in a dialog. +class MultipleImagesDisplay extends StatelessWidget { + /// Default Constructor. + const MultipleImagesDisplay(this.files, {super.key}); + + /// The files containing the images. + final List files; + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: const Text('Gallery'), + // On web the filePath is a blob url + // while on other platforms it is a system path. + content: Center( + child: Row( + children: [ + ...files.map( + (XFile file) => Flexible( + child: kIsWeb + ? Image.network(file.path) + : Image.file(File(file.path)), + ), + ), + ], + ), + ), + actions: [ + TextButton( + child: const Text('Close'), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/open_text_page.dart b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/open_text_page.dart new file mode 100644 index 00000000..0a50be30 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/open_text_page.dart @@ -0,0 +1,86 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; +import 'package:flutter/material.dart'; + +/// Screen that allows the user to select a text file using `openFile`, then +/// displays its contents in a dialog. +class OpenTextPage extends StatelessWidget { + /// Default Constructor + const OpenTextPage({super.key}); + + Future _openTextFile(BuildContext context) async { + const XTypeGroup typeGroup = XTypeGroup( + label: 'text', + extensions: ['txt', 'json'], + ); + final XFile? file = await FileSelectorPlatform.instance.openFile( + acceptedTypeGroups: [typeGroup], + ); + if (file == null) { + // Operation was canceled by the user. + return; + } + final String fileName = file.name; + final String fileContent = await file.readAsString(); + + if (context.mounted) { + await showDialog( + context: context, + builder: (BuildContext context) => TextDisplay(fileName, fileContent), + ); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Open a text file')), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + ), + child: const Text('Press to open a text file (json, txt)'), + onPressed: () => _openTextFile(context), + ), + ], + ), + ), + ); + } +} + +/// Widget that displays a text file in a dialog. +class TextDisplay extends StatelessWidget { + /// Default Constructor. + const TextDisplay(this.fileName, this.fileContent, {super.key}); + + /// The name of the selected file. + final String fileName; + + /// The contents of the text file. + final String fileContent; + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text(fileName), + content: Scrollbar( + child: SingleChildScrollView(child: Text(fileContent)), + ), + actions: [ + TextButton( + child: const Text('Close'), + onPressed: () => Navigator.pop(context), + ), + ], + ); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/save_text_page.dart b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/save_text_page.dart new file mode 100644 index 00000000..bcc26efe --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/lib/save_text_page.dart @@ -0,0 +1,81 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:typed_data'; +import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; +import 'package:flutter/material.dart'; + +/// Screen that allows the user to select a save location using `getSavePath`, +/// then writes text to a file at that location. +class SaveTextPage extends StatelessWidget { + /// Default Constructor + SaveTextPage({super.key}); + + final TextEditingController _nameController = TextEditingController(); + final TextEditingController _contentController = TextEditingController(); + + Future _saveFile() async { + final String fileName = _nameController.text; + final FileSaveLocation? result = await FileSelectorPlatform.instance + .getSaveLocation(options: SaveDialogOptions(suggestedName: fileName)); + // Operation was canceled by the user. + if (result == null) { + return; + } + final String text = _contentController.text; + final Uint8List fileData = Uint8List.fromList(text.codeUnits); + const String fileMimeType = 'text/plain'; + final XFile textFile = XFile.fromData( + fileData, + mimeType: fileMimeType, + name: fileName, + ); + await textFile.saveTo(result.path); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Save text into a file')), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + width: 300, + child: TextField( + minLines: 1, + maxLines: 12, + controller: _nameController, + decoration: const InputDecoration( + hintText: '(Optional) Suggest File Name', + ), + ), + ), + SizedBox( + width: 300, + child: TextField( + minLines: 1, + maxLines: 12, + controller: _contentController, + decoration: const InputDecoration( + hintText: 'Enter File Contents', + ), + ), + ), + const SizedBox(height: 10), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + ), + onPressed: _saveFile, + child: const Text('Press to save a text file'), + ), + ], + ), + ), + ); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/CMakeLists.txt new file mode 100644 index 00000000..9d7224cc --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/CMakeLists.txt @@ -0,0 +1,111 @@ +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +set(BINARY_NAME "example") +set(APPLICATION_ID "com.example.example") + +cmake_policy(SET CMP0063 NEW) + +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Application build +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) +apply_standard_settings(${BINARY_NAME}) +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +add_dependencies(${BINARY_NAME} flutter_assemble) +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + +# Enable the test target. +set(include_file_selector_linux_tests TRUE) +# Provide an alias for the test target using the name expected by repo tooling. +add_custom_target(unit_tests DEPENDS file_selector_linux_test) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/flutter/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..33fd5801 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/flutter/CMakeLists.txt @@ -0,0 +1,87 @@ +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/flutter/generated_plugins.cmake b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..2db3c22a --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/flutter/generated_plugins.cmake @@ -0,0 +1,24 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/main.cc b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/main.cc new file mode 100644 index 00000000..3b03bbf6 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/main.cc @@ -0,0 +1,10 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/my_application.cc b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/my_application.cc new file mode 100644 index 00000000..19727b67 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/my_application.cc @@ -0,0 +1,110 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "example"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments( + project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, + gchar*** arguments, + int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = + my_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new( + my_application_get_type(), "application-id", APPLICATION_ID, nullptr)); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/my_application.h b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/my_application.h new file mode 100644 index 00000000..9ae704a9 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/linux/my_application.h @@ -0,0 +1,22 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/pubspec.yaml b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/pubspec.yaml new file mode 100644 index 00000000..73248a27 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/example/pubspec.yaml @@ -0,0 +1,22 @@ +name: file_selector_linux_example +description: Local testbed for Linux file_selector implementation. +publish_to: 'none' +version: 1.0.0+1 + +environment: + sdk: ^3.8.0 + flutter: ">=3.32.0" + +dependencies: + file_selector_linux: + path: ../ + file_selector_platform_interface: ^2.7.0 + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + +flutter: + uses-material-design: true diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/lib/file_selector_linux.dart b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/lib/file_selector_linux.dart new file mode 100644 index 00000000..f80c9f60 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/lib/file_selector_linux.dart @@ -0,0 +1,187 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; +import 'package:flutter/foundation.dart' show visibleForTesting; + +import 'src/messages.g.dart'; + +/// An implementation of [FileSelectorPlatform] for Linux. +class FileSelectorLinux extends FileSelectorPlatform { + /// Creates a new plugin implementation instance. + FileSelectorLinux({@visibleForTesting FileSelectorApi? api}) + : _hostApi = api ?? FileSelectorApi(); + + final FileSelectorApi _hostApi; + + /// Registers the Linux implementation. + static void registerWith() { + FileSelectorPlatform.instance = FileSelectorLinux(); + } + + @override + Future openFile({ + List? acceptedTypeGroups, + String? initialDirectory, + String? confirmButtonText, + }) async { + final List paths = await _hostApi.showFileChooser( + PlatformFileChooserActionType.open, + PlatformFileChooserOptions( + allowedFileTypes: _platformTypeGroupsFromXTypeGroups( + acceptedTypeGroups, + ), + currentFolderPath: initialDirectory, + acceptButtonLabel: confirmButtonText, + selectMultiple: false, + ), + ); + return paths.isEmpty ? null : XFile(paths.first); + } + + @override + Future> openFiles({ + List? acceptedTypeGroups, + String? initialDirectory, + String? confirmButtonText, + }) async { + final List paths = await _hostApi.showFileChooser( + PlatformFileChooserActionType.open, + PlatformFileChooserOptions( + allowedFileTypes: _platformTypeGroupsFromXTypeGroups( + acceptedTypeGroups, + ), + currentFolderPath: initialDirectory, + acceptButtonLabel: confirmButtonText, + selectMultiple: true, + ), + ); + return paths.map((String path) => XFile(path)).toList(); + } + + @override + Future getSavePath({ + List? acceptedTypeGroups, + String? initialDirectory, + String? suggestedName, + String? confirmButtonText, + }) async { + final FileSaveLocation? location = await getSaveLocation( + acceptedTypeGroups: acceptedTypeGroups, + options: SaveDialogOptions( + initialDirectory: initialDirectory, + suggestedName: suggestedName, + confirmButtonText: confirmButtonText, + ), + ); + return location?.path; + } + + @override + Future getSaveLocation({ + List? acceptedTypeGroups, + SaveDialogOptions options = const SaveDialogOptions(), + }) async { + // TODO(stuartmorgan): Add the selected type group here and return it. See + // https://github.com/flutter/flutter/issues/107093 + final List paths = await _hostApi.showFileChooser( + PlatformFileChooserActionType.save, + PlatformFileChooserOptions( + allowedFileTypes: _platformTypeGroupsFromXTypeGroups( + acceptedTypeGroups, + ), + currentFolderPath: options.initialDirectory, + currentName: options.suggestedName, + acceptButtonLabel: options.confirmButtonText, + createFolders: options.canCreateDirectories, + ), + ); + return paths.isEmpty ? null : FileSaveLocation(paths.first); + } + + @override + Future getDirectoryPath({ + String? initialDirectory, + String? confirmButtonText, + }) async { + return getDirectoryPathWithOptions( + FileDialogOptions( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + ), + ); + } + + @override + Future getDirectoryPathWithOptions(FileDialogOptions options) async { + final List paths = await _hostApi.showFileChooser( + PlatformFileChooserActionType.chooseDirectory, + PlatformFileChooserOptions( + currentFolderPath: options.initialDirectory, + acceptButtonLabel: options.confirmButtonText, + createFolders: options.canCreateDirectories, + selectMultiple: false, + ), + ); + return paths.isEmpty ? null : paths.first; + } + + @override + Future> getDirectoryPaths({ + String? initialDirectory, + String? confirmButtonText, + }) async { + return getDirectoryPathsWithOptions( + FileDialogOptions( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + ), + ); + } + + @override + Future> getDirectoryPathsWithOptions( + FileDialogOptions options, + ) async { + return _hostApi.showFileChooser( + PlatformFileChooserActionType.chooseDirectory, + PlatformFileChooserOptions( + currentFolderPath: options.initialDirectory, + acceptButtonLabel: options.confirmButtonText, + createFolders: options.canCreateDirectories, + selectMultiple: true, + ), + ); + } +} + +List? _platformTypeGroupsFromXTypeGroups( + List? groups, +) { + return groups?.map(_platformTypeGroupFromXTypeGroup).toList(); +} + +PlatformTypeGroup _platformTypeGroupFromXTypeGroup(XTypeGroup group) { + final String label = group.label ?? ''; + if (group.allowsAny) { + return PlatformTypeGroup(label: label, extensions: ['*']); + } + if ((group.extensions?.isEmpty ?? true) && + (group.mimeTypes?.isEmpty ?? true)) { + throw ArgumentError( + 'Provided type group $group does not allow ' + 'all files, but does not set any of the Linux-supported filter ' + 'categories. "extensions" or "mimeTypes" must be non-empty for Linux ' + 'if anything is non-empty.', + ); + } + return PlatformTypeGroup( + label: label, + // Covert to GtkFileFilter's *. format. + extensions: + group.extensions?.map((String extension) => '*.$extension').toList() ?? + [], + mimeTypes: group.mimeTypes ?? [], + ); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/lib/src/messages.g.dart b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/lib/src/messages.g.dart new file mode 100644 index 00000000..592db036 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/lib/src/messages.g.dart @@ -0,0 +1,261 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.1.1), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; + +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; + +PlatformException _createConnectionError(String channelName) { + return PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); +} + +bool _deepEquals(Object? a, Object? b) { + if (a is List && b is List) { + return a.length == b.length && + a.indexed.every( + ((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]), + ); + } + if (a is Map && b is Map) { + return a.length == b.length && + a.entries.every( + (MapEntry entry) => + (b as Map).containsKey(entry.key) && + _deepEquals(entry.value, b[entry.key]), + ); + } + return a == b; +} + +/// A Pigeon representation of the GTK_FILE_CHOOSER_ACTION_* options. +enum PlatformFileChooserActionType { open, chooseDirectory, save } + +/// A Pigeon representation of the Linux portion of an `XTypeGroup`. +class PlatformTypeGroup { + PlatformTypeGroup({ + this.label = '', + this.extensions = const [], + this.mimeTypes = const [], + }); + + String label; + + List extensions; + + List mimeTypes; + + List _toList() { + return [label, extensions, mimeTypes]; + } + + Object encode() { + return _toList(); + } + + static PlatformTypeGroup decode(Object result) { + result as List; + return PlatformTypeGroup( + label: result[0]! as String, + extensions: (result[1] as List?)!.cast(), + mimeTypes: (result[2] as List?)!.cast(), + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformTypeGroup || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Options for GKT file chooser. +/// +/// These correspond to gtk_file_chooser_set_* options. +class PlatformFileChooserOptions { + PlatformFileChooserOptions({ + this.allowedFileTypes, + this.currentFolderPath, + this.currentName, + this.acceptButtonLabel, + this.selectMultiple, + this.createFolders, + }); + + List? allowedFileTypes; + + String? currentFolderPath; + + String? currentName; + + String? acceptButtonLabel; + + /// Whether to allow multiple file selection. + /// + /// Nullable because it does not apply to the "save" action. + bool? selectMultiple; + + /// Whether to allow new folder creation. + /// + /// Nullable because it does not apply to the "open" action. + bool? createFolders; + + List _toList() { + return [ + allowedFileTypes, + currentFolderPath, + currentName, + acceptButtonLabel, + selectMultiple, + createFolders, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformFileChooserOptions decode(Object result) { + result as List; + return PlatformFileChooserOptions( + allowedFileTypes: (result[0] as List?) + ?.cast(), + currentFolderPath: result[1] as String?, + currentName: result[2] as String?, + acceptButtonLabel: result[3] as String?, + selectMultiple: result[4] as bool?, + createFolders: result[5] as bool?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformFileChooserOptions || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else if (value is PlatformFileChooserActionType) { + buffer.putUint8(129); + writeValue(buffer, value.index); + } else if (value is PlatformTypeGroup) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else if (value is PlatformFileChooserOptions) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 129: + final int? value = readValue(buffer) as int?; + return value == null + ? null + : PlatformFileChooserActionType.values[value]; + case 130: + return PlatformTypeGroup.decode(readValue(buffer)!); + case 131: + return PlatformFileChooserOptions.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +class FileSelectorApi { + /// Constructor for [FileSelectorApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + FileSelectorApi({ + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + /// Shows an file chooser with the given [type] and [options], returning the + /// list of selected paths. + /// + /// An empty list corresponds to a cancelled selection. + Future> showFileChooser( + PlatformFileChooserActionType type, + PlatformFileChooserOptions options, + ) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.file_selector_linux.FileSelectorApi.showFileChooser$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [type, options], + ); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as List?)!.cast(); + } + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/CMakeLists.txt new file mode 100644 index 00000000..148819dc --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/CMakeLists.txt @@ -0,0 +1,69 @@ +cmake_minimum_required(VERSION 3.10) +set(PROJECT_NAME "file_selector_linux") +project(${PROJECT_NAME} LANGUAGES CXX) + +cmake_policy(VERSION 3.10...3.24) + +set(PLUGIN_NAME "${PROJECT_NAME}_plugin") + +list(APPEND PLUGIN_SOURCES + "file_selector_plugin.cc" + "messages.g.cc" +) + +add_library(${PLUGIN_NAME} SHARED + ${PLUGIN_SOURCES} +) +apply_standard_settings(${PLUGIN_NAME}) +set_target_properties(${PLUGIN_NAME} PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) +target_include_directories(${PLUGIN_NAME} INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/include") +target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) +target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) + + +# === Tests === + +if(${include_${PROJECT_NAME}_tests}) +if(${CMAKE_VERSION} VERSION_LESS "3.11.0") +message("Unit tests require CMake 3.11.0 or later") +else() +set(TEST_RUNNER "${PROJECT_NAME}_test") +enable_testing() +# TODO(stuartmorgan): Consider using a single shared, pre-checked-in googletest +# instance rather than downloading for each plugin. This approach makes sense +# for a template, but not for a monorepo with many plugins. +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/release-1.11.0.zip +) +# Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +# Disable install commands for gtest so it doesn't end up in the bundle. +set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE) + +FetchContent_MakeAvailable(googletest) + +# The plugin's exported API is not very useful for unit testing, so build the +# sources directly into the test binary rather than using the shared library. +add_executable(${TEST_RUNNER} + test/file_selector_plugin_test.cc + test/test_main.cc + ${PLUGIN_SOURCES} +) +apply_standard_settings(${TEST_RUNNER}) +target_include_directories(${TEST_RUNNER} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") +target_link_libraries(${TEST_RUNNER} PRIVATE flutter) +target_link_libraries(${TEST_RUNNER} PRIVATE PkgConfig::GTK) +target_link_libraries(${TEST_RUNNER} PRIVATE gtest_main gmock) + +include(GoogleTest) +gtest_add_tests(TARGET ${TEST_RUNNER}) +# TODO(stuartmorgan): Ensure that all of the necessary steps are running under +# xvfb, and re-enable this. +#gtest_discover_tests(${TEST_RUNNER}) +endif() # CMake version check +endif() # include_${PROJECT_NAME}_tests diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/file_selector_plugin.cc b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/file_selector_plugin.cc new file mode 100644 index 00000000..bd679792 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/file_selector_plugin.cc @@ -0,0 +1,202 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "include/file_selector_linux/file_selector_plugin.h" + +#include +#include + +#include "file_selector_plugin_private.h" +#include "messages.g.h" + +// Error codes. +const char kBadArgumentsError[] = "Bad Arguments"; +const char kNoScreenError[] = "No Screen"; + +struct _FlFileSelectorPlugin { + GObject parent_instance; + + FlPluginRegistrar* registrar; +}; + +G_DEFINE_TYPE(FlFileSelectorPlugin, fl_file_selector_plugin, G_TYPE_OBJECT) + +// Converts a type group received from Flutter into a GTK file filter. +static GtkFileFilter* type_group_to_filter(FfsPlatformTypeGroup* group) { + g_autoptr(GtkFileFilter) filter = gtk_file_filter_new(); + + const gchar* label = ffs_platform_type_group_get_label(group); + gtk_file_filter_set_name(filter, label); + + FlValue* extensions = ffs_platform_type_group_get_extensions(group); + for (size_t i = 0; i < fl_value_get_length(extensions); i++) { + FlValue* v = fl_value_get_list_value(extensions, i); + const gchar* pattern = fl_value_get_string(v); + gtk_file_filter_add_pattern(filter, pattern); + } + FlValue* mime_types = ffs_platform_type_group_get_mime_types(group); + for (size_t i = 0; i < fl_value_get_length(mime_types); i++) { + FlValue* v = fl_value_get_list_value(mime_types, i); + const gchar* pattern = fl_value_get_string(v); + gtk_file_filter_add_mime_type(filter, pattern); + } + + return GTK_FILE_FILTER(g_object_ref(filter)); +} + +// Creates a GtkFileChooserNative for the given method call details. +static GtkFileChooserNative* create_dialog( + GtkWindow* window, GtkFileChooserAction action, const gchar* title, + const gchar* default_confirm_button_text, + FfsPlatformFileChooserOptions* options) { + const gchar* confirm_button_text = + ffs_platform_file_chooser_options_get_accept_button_label(options); + if (confirm_button_text == nullptr) { + confirm_button_text = default_confirm_button_text; + } + + g_autoptr(GtkFileChooserNative) dialog = + GTK_FILE_CHOOSER_NATIVE(gtk_file_chooser_native_new( + title, window, action, confirm_button_text, "_Cancel")); + + const gboolean* select_multiple = + ffs_platform_file_chooser_options_get_select_multiple(options); + if (select_multiple != nullptr) { + gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), + *select_multiple); + } + + const gchar* current_folder = + ffs_platform_file_chooser_options_get_current_folder_path(options); + if (current_folder != nullptr) { + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), + current_folder); + } + + const gchar* current_name = + ffs_platform_file_chooser_options_get_current_name(options); + if (current_name != nullptr) { + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), current_name); + } + + FlValue* type_groups = + ffs_platform_file_chooser_options_get_allowed_file_types(options); + if (type_groups != nullptr) { + for (size_t i = 0; i < fl_value_get_length(type_groups); i++) { + FlValue* type_group = fl_value_get_list_value(type_groups, i); + GtkFileFilter* filter = type_group_to_filter(FFS_PLATFORM_TYPE_GROUP( + fl_value_get_custom_value_object(type_group))); + if (filter == nullptr) { + return nullptr; + } + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); + } + } + + const gboolean* create_folders = + ffs_platform_file_chooser_options_get_create_folders(options); + if (create_folders != nullptr) { + gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dialog), + *create_folders); + } + + return GTK_FILE_CHOOSER_NATIVE(g_object_ref(dialog)); +} + +GtkFileChooserNative* create_dialog_of_type( + GtkWindow* window, FfsPlatformFileChooserActionType type, + FfsPlatformFileChooserOptions* options) { + switch (type) { + case FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_OPEN: + return create_dialog(window, GTK_FILE_CHOOSER_ACTION_OPEN, "Open File", + "_Open", options); + case FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_CHOOSE_DIRECTORY: + return create_dialog(window, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + "Choose Directory", "_Open", options); + case FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_SAVE: + return create_dialog(window, GTK_FILE_CHOOSER_ACTION_SAVE, "Save File", + "_Save", options); + } + return nullptr; +} + +// Shows the requested dialog type. +static FfsFileSelectorApiShowFileChooserResponse* handle_show_file_chooser( + FfsPlatformFileChooserActionType type, + FfsPlatformFileChooserOptions* options, gpointer user_data) { + FlFileSelectorPlugin* self = FL_FILE_SELECTOR_PLUGIN(user_data); + + FlView* view = fl_plugin_registrar_get_view(self->registrar); + if (view == nullptr) { + return ffs_file_selector_api_show_file_chooser_response_new_error( + kNoScreenError, nullptr, nullptr); + } + GtkWindow* window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))); + + g_autoptr(GtkFileChooserNative) dialog = + create_dialog_of_type(window, type, options); + + if (dialog == nullptr) { + return ffs_file_selector_api_show_file_chooser_response_new_error( + kBadArgumentsError, "Unable to create dialog from arguments", nullptr); + } + return show_file_chooser(GTK_FILE_CHOOSER_NATIVE(dialog), + gtk_native_dialog_run); +} + +FfsFileSelectorApiShowFileChooserResponse* show_file_chooser( + GtkFileChooserNative* dialog, gint (*run_dialog)(GtkNativeDialog*)) { + gint response = run_dialog(GTK_NATIVE_DIALOG(dialog)); + g_autoptr(FlValue) result = fl_value_new_list(); + if (response == GTK_RESPONSE_ACCEPT) { + g_autoptr(GSList) filenames = + gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); + for (GSList* link = filenames; link != nullptr; link = link->next) { + g_autofree gchar* filename = static_cast(link->data); + fl_value_append_take(result, fl_value_new_string(filename)); + } + } + + return ffs_file_selector_api_show_file_chooser_response_new(result); +} + +static void fl_file_selector_plugin_dispose(GObject* object) { + FlFileSelectorPlugin* self = FL_FILE_SELECTOR_PLUGIN(object); + + ffs_file_selector_api_clear_method_handlers( + fl_plugin_registrar_get_messenger(self->registrar), nullptr); + g_clear_object(&self->registrar); + + G_OBJECT_CLASS(fl_file_selector_plugin_parent_class)->dispose(object); +} + +static void fl_file_selector_plugin_class_init( + FlFileSelectorPluginClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_file_selector_plugin_dispose; +} + +static void fl_file_selector_plugin_init(FlFileSelectorPlugin* self) {} + +FlFileSelectorPlugin* fl_file_selector_plugin_new( + FlPluginRegistrar* registrar) { + FlFileSelectorPlugin* self = FL_FILE_SELECTOR_PLUGIN( + g_object_new(fl_file_selector_plugin_get_type(), nullptr)); + + self->registrar = FL_PLUGIN_REGISTRAR(g_object_ref(registrar)); + + static FfsFileSelectorApiVTable api_vtable = { + .show_file_chooser = handle_show_file_chooser, + }; + ffs_file_selector_api_set_method_handlers( + fl_plugin_registrar_get_messenger(registrar), nullptr, &api_vtable, + g_object_ref(self), g_object_unref); + + return self; +} + +void file_selector_plugin_register_with_registrar( + FlPluginRegistrar* registrar) { + FlFileSelectorPlugin* plugin = fl_file_selector_plugin_new(registrar); + g_object_unref(plugin); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/file_selector_plugin_private.h b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/file_selector_plugin_private.h new file mode 100644 index 00000000..9483ae7c --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/file_selector_plugin_private.h @@ -0,0 +1,26 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +#include "include/file_selector_linux/file_selector_plugin.h" +#include "messages.g.h" + +// Creates a GtkFileChooserNative for the given method call. +// +// TODO(stuartmorgan): Make this private/static once the tests are restructured +// as descibed in the file_selector_plugin_test.cc TODOs, and then test through +// the Pigeon API handler instead (making that non-static). This only exists to +// move as much logic as possible behind an entry point currently callable by +// unit tests. +GtkFileChooserNative* create_dialog_of_type( + GtkWindow* window, FfsPlatformFileChooserActionType type, + FfsPlatformFileChooserOptions* options); + +// TODO(stuartmorgan): Fold this into handle_show_file_chooser as part of the +// above TODO. This only exists to allow testing response generation without +// mocking out all of the GTK calls. +FfsFileSelectorApiShowFileChooserResponse* show_file_chooser( + GtkFileChooserNative* dialog, gint (*run_dialog)(GtkNativeDialog*)); diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/include/file_selector_linux/file_selector_plugin.h b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/include/file_selector_linux/file_selector_plugin.h new file mode 100644 index 00000000..350c0605 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/include/file_selector_linux/file_selector_plugin.h @@ -0,0 +1,31 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PLUGINS_FILE_SELECTOR_LINUX_FILE_SELECTOR_PLUGIN_H_ +#define PLUGINS_FILE_SELECTOR_LINUX_FILE_SELECTOR_PLUGIN_H_ + +// A plugin to show native save/open file choosers. + +#include + +G_BEGIN_DECLS + +#ifdef FLUTTER_PLUGIN_IMPL +#define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) +#else +#define FLUTTER_PLUGIN_EXPORT +#endif + +G_DECLARE_FINAL_TYPE(FlFileSelectorPlugin, fl_file_selector_plugin, FL, + FILE_SELECTOR_PLUGIN, GObject) + +FLUTTER_PLUGIN_EXPORT FlFileSelectorPlugin* fl_file_selector_plugin_new( + FlPluginRegistrar* registrar); + +FLUTTER_PLUGIN_EXPORT void file_selector_plugin_register_with_registrar( + FlPluginRegistrar* registrar); + +G_END_DECLS + +#endif // PLUGINS_FILE_SELECTOR_LINUX_FILE_SELECTOR_PLUGIN_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/messages.g.cc b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/messages.g.cc new file mode 100644 index 00000000..5788006d --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/messages.g.cc @@ -0,0 +1,570 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.1.1), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +#include "messages.g.h" + +struct _FfsPlatformTypeGroup { + GObject parent_instance; + + gchar* label; + FlValue* extensions; + FlValue* mime_types; +}; + +G_DEFINE_TYPE(FfsPlatformTypeGroup, ffs_platform_type_group, G_TYPE_OBJECT) + +static void ffs_platform_type_group_dispose(GObject* object) { + FfsPlatformTypeGroup* self = FFS_PLATFORM_TYPE_GROUP(object); + g_clear_pointer(&self->label, g_free); + g_clear_pointer(&self->extensions, fl_value_unref); + g_clear_pointer(&self->mime_types, fl_value_unref); + G_OBJECT_CLASS(ffs_platform_type_group_parent_class)->dispose(object); +} + +static void ffs_platform_type_group_init(FfsPlatformTypeGroup* self) {} + +static void ffs_platform_type_group_class_init( + FfsPlatformTypeGroupClass* klass) { + G_OBJECT_CLASS(klass)->dispose = ffs_platform_type_group_dispose; +} + +FfsPlatformTypeGroup* ffs_platform_type_group_new(const gchar* label, + FlValue* extensions, + FlValue* mime_types) { + FfsPlatformTypeGroup* self = FFS_PLATFORM_TYPE_GROUP( + g_object_new(ffs_platform_type_group_get_type(), nullptr)); + self->label = g_strdup(label); + self->extensions = fl_value_ref(extensions); + self->mime_types = fl_value_ref(mime_types); + return self; +} + +const gchar* ffs_platform_type_group_get_label(FfsPlatformTypeGroup* self) { + g_return_val_if_fail(FFS_IS_PLATFORM_TYPE_GROUP(self), nullptr); + return self->label; +} + +FlValue* ffs_platform_type_group_get_extensions(FfsPlatformTypeGroup* self) { + g_return_val_if_fail(FFS_IS_PLATFORM_TYPE_GROUP(self), nullptr); + return self->extensions; +} + +FlValue* ffs_platform_type_group_get_mime_types(FfsPlatformTypeGroup* self) { + g_return_val_if_fail(FFS_IS_PLATFORM_TYPE_GROUP(self), nullptr); + return self->mime_types; +} + +static FlValue* ffs_platform_type_group_to_list(FfsPlatformTypeGroup* self) { + FlValue* values = fl_value_new_list(); + fl_value_append_take(values, fl_value_new_string(self->label)); + fl_value_append_take(values, fl_value_ref(self->extensions)); + fl_value_append_take(values, fl_value_ref(self->mime_types)); + return values; +} + +static FfsPlatformTypeGroup* ffs_platform_type_group_new_from_list( + FlValue* values) { + FlValue* value0 = fl_value_get_list_value(values, 0); + const gchar* label = fl_value_get_string(value0); + FlValue* value1 = fl_value_get_list_value(values, 1); + FlValue* extensions = value1; + FlValue* value2 = fl_value_get_list_value(values, 2); + FlValue* mime_types = value2; + return ffs_platform_type_group_new(label, extensions, mime_types); +} + +struct _FfsPlatformFileChooserOptions { + GObject parent_instance; + + FlValue* allowed_file_types; + gchar* current_folder_path; + gchar* current_name; + gchar* accept_button_label; + gboolean* select_multiple; + gboolean* create_folders; +}; + +G_DEFINE_TYPE(FfsPlatformFileChooserOptions, ffs_platform_file_chooser_options, + G_TYPE_OBJECT) + +static void ffs_platform_file_chooser_options_dispose(GObject* object) { + FfsPlatformFileChooserOptions* self = + FFS_PLATFORM_FILE_CHOOSER_OPTIONS(object); + g_clear_pointer(&self->allowed_file_types, fl_value_unref); + g_clear_pointer(&self->current_folder_path, g_free); + g_clear_pointer(&self->current_name, g_free); + g_clear_pointer(&self->accept_button_label, g_free); + g_clear_pointer(&self->select_multiple, g_free); + g_clear_pointer(&self->create_folders, g_free); + G_OBJECT_CLASS(ffs_platform_file_chooser_options_parent_class) + ->dispose(object); +} + +static void ffs_platform_file_chooser_options_init( + FfsPlatformFileChooserOptions* self) {} + +static void ffs_platform_file_chooser_options_class_init( + FfsPlatformFileChooserOptionsClass* klass) { + G_OBJECT_CLASS(klass)->dispose = ffs_platform_file_chooser_options_dispose; +} + +FfsPlatformFileChooserOptions* ffs_platform_file_chooser_options_new( + FlValue* allowed_file_types, const gchar* current_folder_path, + const gchar* current_name, const gchar* accept_button_label, + gboolean* select_multiple, gboolean* create_folders) { + FfsPlatformFileChooserOptions* self = FFS_PLATFORM_FILE_CHOOSER_OPTIONS( + g_object_new(ffs_platform_file_chooser_options_get_type(), nullptr)); + if (allowed_file_types != nullptr) { + self->allowed_file_types = fl_value_ref(allowed_file_types); + } else { + self->allowed_file_types = nullptr; + } + if (current_folder_path != nullptr) { + self->current_folder_path = g_strdup(current_folder_path); + } else { + self->current_folder_path = nullptr; + } + if (current_name != nullptr) { + self->current_name = g_strdup(current_name); + } else { + self->current_name = nullptr; + } + if (accept_button_label != nullptr) { + self->accept_button_label = g_strdup(accept_button_label); + } else { + self->accept_button_label = nullptr; + } + if (select_multiple != nullptr) { + self->select_multiple = static_cast(malloc(sizeof(gboolean))); + *self->select_multiple = *select_multiple; + } else { + self->select_multiple = nullptr; + } + if (create_folders != nullptr) { + self->create_folders = static_cast(malloc(sizeof(gboolean))); + *self->create_folders = *create_folders; + } else { + self->create_folders = nullptr; + } + return self; +} + +FlValue* ffs_platform_file_chooser_options_get_allowed_file_types( + FfsPlatformFileChooserOptions* self) { + g_return_val_if_fail(FFS_IS_PLATFORM_FILE_CHOOSER_OPTIONS(self), nullptr); + return self->allowed_file_types; +} + +const gchar* ffs_platform_file_chooser_options_get_current_folder_path( + FfsPlatformFileChooserOptions* self) { + g_return_val_if_fail(FFS_IS_PLATFORM_FILE_CHOOSER_OPTIONS(self), nullptr); + return self->current_folder_path; +} + +const gchar* ffs_platform_file_chooser_options_get_current_name( + FfsPlatformFileChooserOptions* self) { + g_return_val_if_fail(FFS_IS_PLATFORM_FILE_CHOOSER_OPTIONS(self), nullptr); + return self->current_name; +} + +const gchar* ffs_platform_file_chooser_options_get_accept_button_label( + FfsPlatformFileChooserOptions* self) { + g_return_val_if_fail(FFS_IS_PLATFORM_FILE_CHOOSER_OPTIONS(self), nullptr); + return self->accept_button_label; +} + +gboolean* ffs_platform_file_chooser_options_get_select_multiple( + FfsPlatformFileChooserOptions* self) { + g_return_val_if_fail(FFS_IS_PLATFORM_FILE_CHOOSER_OPTIONS(self), nullptr); + return self->select_multiple; +} + +gboolean* ffs_platform_file_chooser_options_get_create_folders( + FfsPlatformFileChooserOptions* self) { + g_return_val_if_fail(FFS_IS_PLATFORM_FILE_CHOOSER_OPTIONS(self), nullptr); + return self->create_folders; +} + +static FlValue* ffs_platform_file_chooser_options_to_list( + FfsPlatformFileChooserOptions* self) { + FlValue* values = fl_value_new_list(); + fl_value_append_take(values, self->allowed_file_types != nullptr + ? fl_value_ref(self->allowed_file_types) + : fl_value_new_null()); + fl_value_append_take(values, + self->current_folder_path != nullptr + ? fl_value_new_string(self->current_folder_path) + : fl_value_new_null()); + fl_value_append_take(values, self->current_name != nullptr + ? fl_value_new_string(self->current_name) + : fl_value_new_null()); + fl_value_append_take(values, + self->accept_button_label != nullptr + ? fl_value_new_string(self->accept_button_label) + : fl_value_new_null()); + fl_value_append_take(values, self->select_multiple != nullptr + ? fl_value_new_bool(*self->select_multiple) + : fl_value_new_null()); + fl_value_append_take(values, self->create_folders != nullptr + ? fl_value_new_bool(*self->create_folders) + : fl_value_new_null()); + return values; +} + +static FfsPlatformFileChooserOptions* +ffs_platform_file_chooser_options_new_from_list(FlValue* values) { + FlValue* value0 = fl_value_get_list_value(values, 0); + FlValue* allowed_file_types = nullptr; + if (fl_value_get_type(value0) != FL_VALUE_TYPE_NULL) { + allowed_file_types = value0; + } + FlValue* value1 = fl_value_get_list_value(values, 1); + const gchar* current_folder_path = nullptr; + if (fl_value_get_type(value1) != FL_VALUE_TYPE_NULL) { + current_folder_path = fl_value_get_string(value1); + } + FlValue* value2 = fl_value_get_list_value(values, 2); + const gchar* current_name = nullptr; + if (fl_value_get_type(value2) != FL_VALUE_TYPE_NULL) { + current_name = fl_value_get_string(value2); + } + FlValue* value3 = fl_value_get_list_value(values, 3); + const gchar* accept_button_label = nullptr; + if (fl_value_get_type(value3) != FL_VALUE_TYPE_NULL) { + accept_button_label = fl_value_get_string(value3); + } + FlValue* value4 = fl_value_get_list_value(values, 4); + gboolean* select_multiple = nullptr; + gboolean select_multiple_value; + if (fl_value_get_type(value4) != FL_VALUE_TYPE_NULL) { + select_multiple_value = fl_value_get_bool(value4); + select_multiple = &select_multiple_value; + } + FlValue* value5 = fl_value_get_list_value(values, 5); + gboolean* create_folders = nullptr; + gboolean create_folders_value; + if (fl_value_get_type(value5) != FL_VALUE_TYPE_NULL) { + create_folders_value = fl_value_get_bool(value5); + create_folders = &create_folders_value; + } + return ffs_platform_file_chooser_options_new( + allowed_file_types, current_folder_path, current_name, + accept_button_label, select_multiple, create_folders); +} + +struct _FfsMessageCodec { + FlStandardMessageCodec parent_instance; +}; + +G_DEFINE_TYPE(FfsMessageCodec, ffs_message_codec, + fl_standard_message_codec_get_type()) + +const int ffs_platform_file_chooser_action_type_type_id = 129; +const int ffs_platform_type_group_type_id = 130; +const int ffs_platform_file_chooser_options_type_id = 131; + +static gboolean ffs_message_codec_write_ffs_platform_file_chooser_action_type( + FlStandardMessageCodec* codec, GByteArray* buffer, FlValue* value, + GError** error) { + uint8_t type = ffs_platform_file_chooser_action_type_type_id; + g_byte_array_append(buffer, &type, sizeof(uint8_t)); + return fl_standard_message_codec_write_value(codec, buffer, value, error); +} + +static gboolean ffs_message_codec_write_ffs_platform_type_group( + FlStandardMessageCodec* codec, GByteArray* buffer, + FfsPlatformTypeGroup* value, GError** error) { + uint8_t type = ffs_platform_type_group_type_id; + g_byte_array_append(buffer, &type, sizeof(uint8_t)); + g_autoptr(FlValue) values = ffs_platform_type_group_to_list(value); + return fl_standard_message_codec_write_value(codec, buffer, values, error); +} + +static gboolean ffs_message_codec_write_ffs_platform_file_chooser_options( + FlStandardMessageCodec* codec, GByteArray* buffer, + FfsPlatformFileChooserOptions* value, GError** error) { + uint8_t type = ffs_platform_file_chooser_options_type_id; + g_byte_array_append(buffer, &type, sizeof(uint8_t)); + g_autoptr(FlValue) values = ffs_platform_file_chooser_options_to_list(value); + return fl_standard_message_codec_write_value(codec, buffer, values, error); +} + +static gboolean ffs_message_codec_write_value(FlStandardMessageCodec* codec, + GByteArray* buffer, + FlValue* value, GError** error) { + if (fl_value_get_type(value) == FL_VALUE_TYPE_CUSTOM) { + switch (fl_value_get_custom_type(value)) { + case ffs_platform_file_chooser_action_type_type_id: + return ffs_message_codec_write_ffs_platform_file_chooser_action_type( + codec, buffer, + reinterpret_cast( + const_cast(fl_value_get_custom_value(value))), + error); + case ffs_platform_type_group_type_id: + return ffs_message_codec_write_ffs_platform_type_group( + codec, buffer, + FFS_PLATFORM_TYPE_GROUP(fl_value_get_custom_value_object(value)), + error); + case ffs_platform_file_chooser_options_type_id: + return ffs_message_codec_write_ffs_platform_file_chooser_options( + codec, buffer, + FFS_PLATFORM_FILE_CHOOSER_OPTIONS( + fl_value_get_custom_value_object(value)), + error); + } + } + + return FL_STANDARD_MESSAGE_CODEC_CLASS(ffs_message_codec_parent_class) + ->write_value(codec, buffer, value, error); +} + +static FlValue* ffs_message_codec_read_ffs_platform_file_chooser_action_type( + FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, + GError** error) { + return fl_value_new_custom( + ffs_platform_file_chooser_action_type_type_id, + fl_standard_message_codec_read_value(codec, buffer, offset, error), + (GDestroyNotify)fl_value_unref); +} + +static FlValue* ffs_message_codec_read_ffs_platform_type_group( + FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, + GError** error) { + g_autoptr(FlValue) values = + fl_standard_message_codec_read_value(codec, buffer, offset, error); + if (values == nullptr) { + return nullptr; + } + + g_autoptr(FfsPlatformTypeGroup) value = + ffs_platform_type_group_new_from_list(values); + if (value == nullptr) { + g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED, + "Invalid data received for MessageData"); + return nullptr; + } + + return fl_value_new_custom_object(ffs_platform_type_group_type_id, + G_OBJECT(value)); +} + +static FlValue* ffs_message_codec_read_ffs_platform_file_chooser_options( + FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, + GError** error) { + g_autoptr(FlValue) values = + fl_standard_message_codec_read_value(codec, buffer, offset, error); + if (values == nullptr) { + return nullptr; + } + + g_autoptr(FfsPlatformFileChooserOptions) value = + ffs_platform_file_chooser_options_new_from_list(values); + if (value == nullptr) { + g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED, + "Invalid data received for MessageData"); + return nullptr; + } + + return fl_value_new_custom_object(ffs_platform_file_chooser_options_type_id, + G_OBJECT(value)); +} + +static FlValue* ffs_message_codec_read_value_of_type( + FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, int type, + GError** error) { + switch (type) { + case ffs_platform_file_chooser_action_type_type_id: + return ffs_message_codec_read_ffs_platform_file_chooser_action_type( + codec, buffer, offset, error); + case ffs_platform_type_group_type_id: + return ffs_message_codec_read_ffs_platform_type_group(codec, buffer, + offset, error); + case ffs_platform_file_chooser_options_type_id: + return ffs_message_codec_read_ffs_platform_file_chooser_options( + codec, buffer, offset, error); + default: + return FL_STANDARD_MESSAGE_CODEC_CLASS(ffs_message_codec_parent_class) + ->read_value_of_type(codec, buffer, offset, type, error); + } +} + +static void ffs_message_codec_init(FfsMessageCodec* self) {} + +static void ffs_message_codec_class_init(FfsMessageCodecClass* klass) { + FL_STANDARD_MESSAGE_CODEC_CLASS(klass)->write_value = + ffs_message_codec_write_value; + FL_STANDARD_MESSAGE_CODEC_CLASS(klass)->read_value_of_type = + ffs_message_codec_read_value_of_type; +} + +static FfsMessageCodec* ffs_message_codec_new() { + FfsMessageCodec* self = + FFS_MESSAGE_CODEC(g_object_new(ffs_message_codec_get_type(), nullptr)); + return self; +} + +struct _FfsFileSelectorApiShowFileChooserResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE(FfsFileSelectorApiShowFileChooserResponse, + ffs_file_selector_api_show_file_chooser_response, G_TYPE_OBJECT) + +static void ffs_file_selector_api_show_file_chooser_response_dispose( + GObject* object) { + FfsFileSelectorApiShowFileChooserResponse* self = + FFS_FILE_SELECTOR_API_SHOW_FILE_CHOOSER_RESPONSE(object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS(ffs_file_selector_api_show_file_chooser_response_parent_class) + ->dispose(object); +} + +static void ffs_file_selector_api_show_file_chooser_response_init( + FfsFileSelectorApiShowFileChooserResponse* self) {} + +static void ffs_file_selector_api_show_file_chooser_response_class_init( + FfsFileSelectorApiShowFileChooserResponseClass* klass) { + G_OBJECT_CLASS(klass)->dispose = + ffs_file_selector_api_show_file_chooser_response_dispose; +} + +FfsFileSelectorApiShowFileChooserResponse* +ffs_file_selector_api_show_file_chooser_response_new(FlValue* return_value) { + FfsFileSelectorApiShowFileChooserResponse* self = + FFS_FILE_SELECTOR_API_SHOW_FILE_CHOOSER_RESPONSE(g_object_new( + ffs_file_selector_api_show_file_chooser_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_ref(return_value)); + return self; +} + +FfsFileSelectorApiShowFileChooserResponse* +ffs_file_selector_api_show_file_chooser_response_new_error(const gchar* code, + const gchar* message, + FlValue* details) { + FfsFileSelectorApiShowFileChooserResponse* self = + FFS_FILE_SELECTOR_API_SHOW_FILE_CHOOSER_RESPONSE(g_object_new( + ffs_file_selector_api_show_file_chooser_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, + fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) + : fl_value_new_null()); + return self; +} + +struct _FfsFileSelectorApi { + GObject parent_instance; + + const FfsFileSelectorApiVTable* vtable; + gpointer user_data; + GDestroyNotify user_data_free_func; +}; + +G_DEFINE_TYPE(FfsFileSelectorApi, ffs_file_selector_api, G_TYPE_OBJECT) + +static void ffs_file_selector_api_dispose(GObject* object) { + FfsFileSelectorApi* self = FFS_FILE_SELECTOR_API(object); + if (self->user_data != nullptr) { + self->user_data_free_func(self->user_data); + } + self->user_data = nullptr; + G_OBJECT_CLASS(ffs_file_selector_api_parent_class)->dispose(object); +} + +static void ffs_file_selector_api_init(FfsFileSelectorApi* self) {} + +static void ffs_file_selector_api_class_init(FfsFileSelectorApiClass* klass) { + G_OBJECT_CLASS(klass)->dispose = ffs_file_selector_api_dispose; +} + +static FfsFileSelectorApi* ffs_file_selector_api_new( + const FfsFileSelectorApiVTable* vtable, gpointer user_data, + GDestroyNotify user_data_free_func) { + FfsFileSelectorApi* self = FFS_FILE_SELECTOR_API( + g_object_new(ffs_file_selector_api_get_type(), nullptr)); + self->vtable = vtable; + self->user_data = user_data; + self->user_data_free_func = user_data_free_func; + return self; +} + +static void ffs_file_selector_api_show_file_chooser_cb( + FlBasicMessageChannel* channel, FlValue* message_, + FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + FfsFileSelectorApi* self = FFS_FILE_SELECTOR_API(user_data); + + if (self->vtable == nullptr || self->vtable->show_file_chooser == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + FfsPlatformFileChooserActionType type = + static_cast( + fl_value_get_int(reinterpret_cast( + const_cast(fl_value_get_custom_value(value0))))); + FlValue* value1 = fl_value_get_list_value(message_, 1); + FfsPlatformFileChooserOptions* options = FFS_PLATFORM_FILE_CHOOSER_OPTIONS( + fl_value_get_custom_value_object(value1)); + g_autoptr(FfsFileSelectorApiShowFileChooserResponse) response = + self->vtable->show_file_chooser(type, options, self->user_data); + if (response == nullptr) { + g_warning("No response returned to %s.%s", "FileSelectorApi", + "showFileChooser"); + return; + } + + g_autoptr(GError) error = NULL; + if (!fl_basic_message_channel_respond(channel, response_handle, + response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "FileSelectorApi", + "showFileChooser", error->message); + } +} + +void ffs_file_selector_api_set_method_handlers( + FlBinaryMessenger* messenger, const gchar* suffix, + const FfsFileSelectorApiVTable* vtable, gpointer user_data, + GDestroyNotify user_data_free_func) { + g_autofree gchar* dot_suffix = + suffix != nullptr ? g_strdup_printf(".%s", suffix) : g_strdup(""); + g_autoptr(FfsFileSelectorApi) api_data = + ffs_file_selector_api_new(vtable, user_data, user_data_free_func); + + g_autoptr(FfsMessageCodec) codec = ffs_message_codec_new(); + g_autofree gchar* show_file_chooser_channel_name = g_strdup_printf( + "dev.flutter.pigeon.file_selector_linux.FileSelectorApi.showFileChooser%" + "s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) show_file_chooser_channel = + fl_basic_message_channel_new(messenger, show_file_chooser_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + show_file_chooser_channel, ffs_file_selector_api_show_file_chooser_cb, + g_object_ref(api_data), g_object_unref); +} + +void ffs_file_selector_api_clear_method_handlers(FlBinaryMessenger* messenger, + const gchar* suffix) { + g_autofree gchar* dot_suffix = + suffix != nullptr ? g_strdup_printf(".%s", suffix) : g_strdup(""); + + g_autoptr(FfsMessageCodec) codec = ffs_message_codec_new(); + g_autofree gchar* show_file_chooser_channel_name = g_strdup_printf( + "dev.flutter.pigeon.file_selector_linux.FileSelectorApi.showFileChooser%" + "s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) show_file_chooser_channel = + fl_basic_message_channel_new(messenger, show_file_chooser_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(show_file_chooser_channel, + nullptr, nullptr, nullptr); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/messages.g.h b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/messages.g.h new file mode 100644 index 00000000..3d5c8c65 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/linux/messages.g.h @@ -0,0 +1,269 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.1.1), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +#ifndef PIGEON_MESSAGES_G_H_ +#define PIGEON_MESSAGES_G_H_ + +#include + +G_BEGIN_DECLS + +/** + * FfsPlatformFileChooserActionType: + * FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_OPEN: + * FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_CHOOSE_DIRECTORY: + * FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_SAVE: + * + * A Pigeon representation of the GTK_FILE_CHOOSER_ACTION_* options. + */ +typedef enum { + FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_OPEN = 0, + FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_CHOOSE_DIRECTORY = 1, + FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_SAVE = 2 +} FfsPlatformFileChooserActionType; + +/** + * FfsPlatformTypeGroup: + * + * A Pigeon representation of the Linux portion of an `XTypeGroup`. + */ + +G_DECLARE_FINAL_TYPE(FfsPlatformTypeGroup, ffs_platform_type_group, FFS, + PLATFORM_TYPE_GROUP, GObject) + +/** + * ffs_platform_type_group_new: + * label: field in this object. + * extensions: field in this object. + * mime_types: field in this object. + * + * Creates a new #PlatformTypeGroup object. + * + * Returns: a new #FfsPlatformTypeGroup + */ +FfsPlatformTypeGroup* ffs_platform_type_group_new(const gchar* label, + FlValue* extensions, + FlValue* mime_types); + +/** + * ffs_platform_type_group_get_label + * @object: a #FfsPlatformTypeGroup. + * + * Gets the value of the label field of @object. + * + * Returns: the field value. + */ +const gchar* ffs_platform_type_group_get_label(FfsPlatformTypeGroup* object); + +/** + * ffs_platform_type_group_get_extensions + * @object: a #FfsPlatformTypeGroup. + * + * Gets the value of the extensions field of @object. + * + * Returns: the field value. + */ +FlValue* ffs_platform_type_group_get_extensions(FfsPlatformTypeGroup* object); + +/** + * ffs_platform_type_group_get_mime_types + * @object: a #FfsPlatformTypeGroup. + * + * Gets the value of the mimeTypes field of @object. + * + * Returns: the field value. + */ +FlValue* ffs_platform_type_group_get_mime_types(FfsPlatformTypeGroup* object); + +/** + * FfsPlatformFileChooserOptions: + * + * Options for GKT file chooser. + * + * These correspond to gtk_file_chooser_set_* options. + */ + +G_DECLARE_FINAL_TYPE(FfsPlatformFileChooserOptions, + ffs_platform_file_chooser_options, FFS, + PLATFORM_FILE_CHOOSER_OPTIONS, GObject) + +/** + * ffs_platform_file_chooser_options_new: + * allowed_file_types: field in this object. + * current_folder_path: field in this object. + * current_name: field in this object. + * accept_button_label: field in this object. + * select_multiple: field in this object. + * create_folders: field in this object. + * + * Creates a new #PlatformFileChooserOptions object. + * + * Returns: a new #FfsPlatformFileChooserOptions + */ +FfsPlatformFileChooserOptions* ffs_platform_file_chooser_options_new( + FlValue* allowed_file_types, const gchar* current_folder_path, + const gchar* current_name, const gchar* accept_button_label, + gboolean* select_multiple, gboolean* create_folders); + +/** + * ffs_platform_file_chooser_options_get_allowed_file_types + * @object: a #FfsPlatformFileChooserOptions. + * + * Gets the value of the allowedFileTypes field of @object. + * + * Returns: the field value. + */ +FlValue* ffs_platform_file_chooser_options_get_allowed_file_types( + FfsPlatformFileChooserOptions* object); + +/** + * ffs_platform_file_chooser_options_get_current_folder_path + * @object: a #FfsPlatformFileChooserOptions. + * + * Gets the value of the currentFolderPath field of @object. + * + * Returns: the field value. + */ +const gchar* ffs_platform_file_chooser_options_get_current_folder_path( + FfsPlatformFileChooserOptions* object); + +/** + * ffs_platform_file_chooser_options_get_current_name + * @object: a #FfsPlatformFileChooserOptions. + * + * Gets the value of the currentName field of @object. + * + * Returns: the field value. + */ +const gchar* ffs_platform_file_chooser_options_get_current_name( + FfsPlatformFileChooserOptions* object); + +/** + * ffs_platform_file_chooser_options_get_accept_button_label + * @object: a #FfsPlatformFileChooserOptions. + * + * Gets the value of the acceptButtonLabel field of @object. + * + * Returns: the field value. + */ +const gchar* ffs_platform_file_chooser_options_get_accept_button_label( + FfsPlatformFileChooserOptions* object); + +/** + * ffs_platform_file_chooser_options_get_select_multiple + * @object: a #FfsPlatformFileChooserOptions. + * + * Whether to allow multiple file selection. + * + * Nullable because it does not apply to the "save" action. + * + * Returns: the field value. + */ +gboolean* ffs_platform_file_chooser_options_get_select_multiple( + FfsPlatformFileChooserOptions* object); + +/** + * ffs_platform_file_chooser_options_get_create_folders + * @object: a #FfsPlatformFileChooserOptions. + * + * Whether to allow new folder creation. + * + * Nullable because it does not apply to the "open" action. + * + * Returns: the field value. + */ +gboolean* ffs_platform_file_chooser_options_get_create_folders( + FfsPlatformFileChooserOptions* object); + +G_DECLARE_FINAL_TYPE(FfsMessageCodec, ffs_message_codec, FFS, MESSAGE_CODEC, + FlStandardMessageCodec) + +/** + * Custom type ID constants: + * + * Constants used to identify custom types in the codec. + * They are used in the codec to encode and decode custom types. + * They may be used in custom object creation functions to identify the type. + */ +extern const int ffs_platform_file_chooser_action_type_type_id; +extern const int ffs_platform_type_group_type_id; +extern const int ffs_platform_file_chooser_options_type_id; + +G_DECLARE_FINAL_TYPE(FfsFileSelectorApi, ffs_file_selector_api, FFS, + FILE_SELECTOR_API, GObject) + +G_DECLARE_FINAL_TYPE(FfsFileSelectorApiShowFileChooserResponse, + ffs_file_selector_api_show_file_chooser_response, FFS, + FILE_SELECTOR_API_SHOW_FILE_CHOOSER_RESPONSE, GObject) + +/** + * ffs_file_selector_api_show_file_chooser_response_new: + * + * Creates a new response to FileSelectorApi.showFileChooser. + * + * Returns: a new #FfsFileSelectorApiShowFileChooserResponse + */ +FfsFileSelectorApiShowFileChooserResponse* +ffs_file_selector_api_show_file_chooser_response_new(FlValue* return_value); + +/** + * ffs_file_selector_api_show_file_chooser_response_new_error: + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Creates a new error response to FileSelectorApi.showFileChooser. + * + * Returns: a new #FfsFileSelectorApiShowFileChooserResponse + */ +FfsFileSelectorApiShowFileChooserResponse* +ffs_file_selector_api_show_file_chooser_response_new_error(const gchar* code, + const gchar* message, + FlValue* details); + +/** + * FfsFileSelectorApiVTable: + * + * Table of functions exposed by FileSelectorApi to be implemented by the API + * provider. + */ +typedef struct { + FfsFileSelectorApiShowFileChooserResponse* (*show_file_chooser)( + FfsPlatformFileChooserActionType type, + FfsPlatformFileChooserOptions* options, gpointer user_data); +} FfsFileSelectorApiVTable; + +/** + * ffs_file_selector_api_set_method_handlers: + * + * @messenger: an #FlBinaryMessenger. + * @suffix: (allow-none): a suffix to add to the API or %NULL for none. + * @vtable: implementations of the methods in this API. + * @user_data: (closure): user data to pass to the functions in @vtable. + * @user_data_free_func: (allow-none): a function which gets called to free + * @user_data, or %NULL. + * + * Connects the method handlers in the FileSelectorApi API. + */ +void ffs_file_selector_api_set_method_handlers( + FlBinaryMessenger* messenger, const gchar* suffix, + const FfsFileSelectorApiVTable* vtable, gpointer user_data, + GDestroyNotify user_data_free_func); + +/** + * ffs_file_selector_api_clear_method_handlers: + * + * @messenger: an #FlBinaryMessenger. + * @suffix: (allow-none): a suffix to add to the API or %NULL for none. + * + * Clears the method handlers in the FileSelectorApi API. + */ +void ffs_file_selector_api_clear_method_handlers(FlBinaryMessenger* messenger, + const gchar* suffix); + +G_END_DECLS + +#endif // PIGEON_MESSAGES_G_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/pigeons/copyright.txt b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/pigeons/copyright.txt new file mode 100644 index 00000000..07e5f859 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/pigeons/copyright.txt @@ -0,0 +1,3 @@ +Copyright 2013 The Flutter Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/pigeons/messages.dart b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/pigeons/messages.dart new file mode 100644 index 00000000..e700c6ae --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/pigeons/messages.dart @@ -0,0 +1,71 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +import 'package:pigeon/pigeon.dart'; + +@ConfigurePigeon( + PigeonOptions( + input: 'pigeons/messages.dart', + gobjectHeaderOut: 'linux/messages.g.h', + gobjectSourceOut: 'linux/messages.g.cc', + gobjectOptions: GObjectOptions(module: 'Ffs'), + dartOut: 'lib/src/messages.g.dart', + copyrightHeader: 'pigeons/copyright.txt', + ), +) +/// A Pigeon representation of the GTK_FILE_CHOOSER_ACTION_* options. +enum PlatformFileChooserActionType { open, chooseDirectory, save } + +/// A Pigeon representation of the Linux portion of an `XTypeGroup`. +class PlatformTypeGroup { + const PlatformTypeGroup({ + this.label = '', + this.extensions = const [], + this.mimeTypes = const [], + }); + + final String label; + final List extensions; + final List mimeTypes; +} + +/// Options for GKT file chooser. +/// +/// These correspond to gtk_file_chooser_set_* options. +class PlatformFileChooserOptions { + PlatformFileChooserOptions({ + required this.allowedFileTypes, + required this.currentFolderPath, + required this.currentName, + required this.acceptButtonLabel, + this.selectMultiple, + this.createFolders, + }); + + final List? allowedFileTypes; + final String? currentFolderPath; + final String? currentName; + final String? acceptButtonLabel; + + /// Whether to allow multiple file selection. + /// + /// Nullable because it does not apply to the "save" action. + final bool? selectMultiple; + + /// Whether to allow new folder creation. + /// + /// Nullable because it does not apply to the "open" action. + final bool? createFolders; +} + +@HostApi() +abstract class FileSelectorApi { + /// Shows an file chooser with the given [type] and [options], returning the + /// list of selected paths. + /// + /// An empty list corresponds to a cancelled selection. + List showFileChooser( + PlatformFileChooserActionType type, + PlatformFileChooserOptions options, + ); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/pubspec.yaml b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/pubspec.yaml new file mode 100644 index 00000000..810d3789 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux/pubspec.yaml @@ -0,0 +1,33 @@ +name: file_selector_linux +description: Liunx implementation of the file_selector plugin. +repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_linux +issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22 +version: 0.9.4 + +environment: + sdk: ^3.8.0 + flutter: ">=3.32.0" + +flutter: + plugin: + implements: file_selector + platforms: + linux: + pluginClass: FileSelectorPlugin + dartPluginClass: FileSelectorLinux + +dependencies: + cross_file: ^0.3.1 + file_selector_platform_interface: ^2.7.0 + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + pigeon: ^26.1.0 + +topics: + - files + - file-selection + - file-selector diff --git a/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/AUTHORS b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/AUTHORS new file mode 100644 index 00000000..26e81c7f --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/AUTHORS @@ -0,0 +1,7 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +Alexandre Zollinger Chohfi diff --git a/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/CHANGELOG.md b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/CHANGELOG.md new file mode 100644 index 00000000..95207a3b --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/CHANGELOG.md @@ -0,0 +1,22 @@ +## 0.2.2 + +* Adds support for `getMultiVideoWithOptions`. +* Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. + +## 0.2.1+2 + +* Updates minimum supported SDK version to Flutter 3.22/Dart 3.4. +* Fixes `getMedia` mime types. + +## 0.2.1+1 + +* Adds pub topics to package metadata. +* Updates minimum supported SDK version to Flutter 3.7/Dart 2.19. + +## 0.2.1 + +* Adds `getMedia` method. + +## 0.2.0 + +* Implements initial Linux support. diff --git a/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/lib/main.dart b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/lib/main.dart new file mode 100644 index 00000000..b62d3913 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/lib/main.dart @@ -0,0 +1,564 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'dart:async'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; +import 'package:mime/mime.dart'; +import 'package:video_player/video_player.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return const MaterialApp( + title: 'Image Picker Demo', + home: MyHomePage(title: 'Image Picker Example'), + ); + } +} + +class MyHomePage extends StatefulWidget { + const MyHomePage({super.key, this.title}); + + final String? title; + + @override + State createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + List? _mediaFileList; + + // This must be called from within a setState() callback + void _setImageFileListFromFile(XFile? value) { + _mediaFileList = value == null ? null : [value]; + } + + dynamic _pickImageError; + bool _isVideo = false; + + VideoPlayerController? _controller; + VideoPlayerController? _toBeDisposed; + String? _retrieveDataError; + + final ImagePickerPlatform _picker = ImagePickerPlatform.instance; + final TextEditingController maxWidthController = TextEditingController(); + final TextEditingController maxHeightController = TextEditingController(); + final TextEditingController qualityController = TextEditingController(); + + Future _playVideo(XFile? file) async { + if (file != null && mounted) { + await _disposeVideoController(); + final VideoPlayerController controller = + VideoPlayerController.file(File(file.path)); + _controller = controller; + await controller.setVolume(1.0); + await controller.initialize(); + await controller.setLooping(true); + await controller.play(); + setState(() {}); + } + } + + Future _onImageButtonPressed( + ImageSource source, { + required BuildContext context, + bool allowMultiple = false, + bool isMedia = false, + }) async { + if (_controller != null) { + await _controller!.setVolume(0.0); + } + if (context.mounted) { + if (_isVideo) { + final List files; + if (allowMultiple) { + files = await _picker.getMultiVideoWithOptions(); + } else { + final XFile? file = await _picker.getVideo( + source: source, maxDuration: const Duration(seconds: 10)); + files = [if (file != null) file]; + } + if (files.isNotEmpty && context.mounted) { + _showPickedSnackBar(context, files); + // Just play the first file, to keep the example simple. + await _playVideo(files.first); + } + } else if (allowMultiple) { + await _displayPickImageDialog(context, + (double? maxWidth, double? maxHeight, int? quality) async { + try { + final ImageOptions imageOptions = ImageOptions( + maxWidth: maxWidth, + maxHeight: maxHeight, + imageQuality: quality, + ); + final List pickedFileList = isMedia + ? await _picker.getMedia( + options: MediaOptions( + allowMultiple: allowMultiple, + imageOptions: imageOptions, + ), + ) + : await _picker.getMultiImageWithOptions( + options: MultiImagePickerOptions( + imageOptions: imageOptions, + ), + ); + if (pickedFileList.isNotEmpty && context.mounted) { + _showPickedSnackBar(context, pickedFileList); + } + setState(() { + _mediaFileList = pickedFileList; + }); + } catch (e) { + setState(() { + _pickImageError = e; + }); + } + }); + } else if (isMedia) { + await _displayPickImageDialog(context, + (double? maxWidth, double? maxHeight, int? quality) async { + try { + final List pickedFileList = []; + final XFile? media = _firstOrNull(await _picker.getMedia( + options: MediaOptions( + allowMultiple: allowMultiple, + imageOptions: ImageOptions( + maxWidth: maxWidth, + maxHeight: maxHeight, + imageQuality: quality, + )), + )); + + if (media != null) { + pickedFileList.add(media); + setState(() { + _mediaFileList = pickedFileList; + }); + } + } catch (e) { + setState(() => _pickImageError = e); + } + }); + } else { + await _displayPickImageDialog(context, + (double? maxWidth, double? maxHeight, int? quality) async { + try { + final XFile? pickedFile = await _picker.getImageFromSource( + source: source, + options: ImagePickerOptions( + maxWidth: maxWidth, + maxHeight: maxHeight, + imageQuality: quality, + ), + ); + if (pickedFile != null && context.mounted) { + _showPickedSnackBar(context, [pickedFile]); + } + setState(() => _setImageFileListFromFile(pickedFile)); + } catch (e) { + setState(() => _pickImageError = e); + } + }); + } + } + } + + @override + void deactivate() { + if (_controller != null) { + _controller!.setVolume(0.0); + _controller!.pause(); + } + super.deactivate(); + } + + @override + void dispose() { + _disposeVideoController(); + maxWidthController.dispose(); + maxHeightController.dispose(); + qualityController.dispose(); + super.dispose(); + } + + Future _disposeVideoController() async { + if (_toBeDisposed != null) { + await _toBeDisposed!.dispose(); + } + _toBeDisposed = _controller; + _controller = null; + } + + Widget _previewVideo() { + final Text? retrieveError = _getRetrieveErrorWidget(); + if (retrieveError != null) { + return retrieveError; + } + if (_controller == null) { + return const Text( + 'You have not yet picked a video', + textAlign: TextAlign.center, + ); + } + return Padding( + padding: const EdgeInsets.all(10.0), + child: AspectRatioVideo(_controller), + ); + } + + Widget _previewImages() { + final Text? retrieveError = _getRetrieveErrorWidget(); + if (retrieveError != null) { + return retrieveError; + } + if (_mediaFileList != null) { + return Semantics( + label: 'image_picker_example_picked_images', + child: ListView.builder( + key: UniqueKey(), + itemBuilder: (BuildContext context, int index) { + final XFile image = _mediaFileList![index]; + final String? mime = lookupMimeType(_mediaFileList![index].path); + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(image.name, + key: const Key('image_picker_example_picked_image_name')), + Semantics( + label: 'image_picker_example_picked_image', + child: mime == null || mime.startsWith('image/') + ? Image.file( + File(_mediaFileList![index].path), + errorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return const Center( + child: + Text('This image type is not supported')); + }, + ) + : _buildInlineVideoPlayer(index), + ), + ], + ); + }, + itemCount: _mediaFileList!.length, + ), + ); + } else if (_pickImageError != null) { + return Text( + 'Pick image error: $_pickImageError', + textAlign: TextAlign.center, + ); + } else { + return const Text( + 'You have not yet picked an image.', + textAlign: TextAlign.center, + ); + } + } + + Widget _buildInlineVideoPlayer(int index) { + final VideoPlayerController controller = + VideoPlayerController.file(File(_mediaFileList![index].path)); + controller.setVolume(1.0); + controller.initialize(); + controller.setLooping(true); + controller.play(); + return Center(child: AspectRatioVideo(controller)); + } + + Widget _handlePreview() { + if (_isVideo) { + return _previewVideo(); + } else { + return _previewImages(); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title!), + ), + body: Align( + alignment: Alignment.topCenter, + child: _handlePreview(), + ), + floatingActionButton: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Semantics( + label: 'image_picker_example_from_gallery', + child: FloatingActionButton.extended( + key: const Key('image_picker_example_from_gallery'), + onPressed: () { + _isVideo = false; + _onImageButtonPressed(ImageSource.gallery, context: context); + }, + heroTag: 'image0', + tooltip: 'Pick image from gallery', + label: const Text('Pick image from gallery'), + icon: const Icon(Icons.photo), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton.extended( + onPressed: () { + _isVideo = false; + _onImageButtonPressed( + ImageSource.gallery, + context: context, + allowMultiple: true, + ); + }, + heroTag: 'image1', + tooltip: 'Pick multiple images', + label: const Text('Pick multiple images'), + icon: const Icon(Icons.photo_library), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton.extended( + onPressed: () { + _isVideo = false; + _onImageButtonPressed( + ImageSource.gallery, + context: context, + isMedia: true, + ); + }, + heroTag: 'media', + tooltip: 'Pick item from gallery', + label: const Text('Pick item from gallery'), + icon: const Icon(Icons.photo_outlined), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton.extended( + onPressed: () { + _isVideo = false; + _onImageButtonPressed( + ImageSource.gallery, + context: context, + allowMultiple: true, + isMedia: true, + ); + }, + heroTag: 'multipleMedia', + tooltip: 'Pick multiple items', + label: const Text('Pick multiple items'), + icon: const Icon(Icons.photo_library_outlined), + ), + ), + if (_picker.supportsImageSource(ImageSource.camera)) + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton.extended( + onPressed: () { + _isVideo = false; + _onImageButtonPressed(ImageSource.camera, context: context); + }, + heroTag: 'image2', + tooltip: 'Take a photo', + label: const Text('Take a photo'), + icon: const Icon(Icons.camera_alt), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton.extended( + backgroundColor: Colors.red, + onPressed: () { + _isVideo = true; + _onImageButtonPressed(ImageSource.gallery, context: context); + }, + heroTag: 'video', + tooltip: 'Pick video from gallery', + label: const Text('Pick video from gallery'), + icon: const Icon(Icons.video_file), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton.extended( + backgroundColor: Colors.red, + onPressed: () { + _isVideo = true; + _onImageButtonPressed(ImageSource.gallery, + context: context, allowMultiple: true); + }, + heroTag: 'multiVideo', + tooltip: 'Pick multiple videos', + label: const Text('Pick multiple videos'), + icon: const Icon(Icons.video_library), + ), + ), + if (_picker.supportsImageSource(ImageSource.camera)) + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton.extended( + backgroundColor: Colors.red, + onPressed: () { + _isVideo = true; + _onImageButtonPressed(ImageSource.camera, context: context); + }, + heroTag: 'takeVideo', + tooltip: 'Take a video', + label: const Text('Take a video'), + icon: const Icon(Icons.videocam), + ), + ), + ], + ), + ); + } + + Text? _getRetrieveErrorWidget() { + if (_retrieveDataError != null) { + final Text result = Text(_retrieveDataError!); + _retrieveDataError = null; + return result; + } + return null; + } + + Future _displayPickImageDialog( + BuildContext context, OnPickImageCallback onPick) async { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Add optional parameters'), + content: Column( + children: [ + TextField( + controller: maxWidthController, + keyboardType: + const TextInputType.numberWithOptions(decimal: true), + decoration: const InputDecoration( + hintText: 'Enter maxWidth if desired'), + ), + TextField( + controller: maxHeightController, + keyboardType: + const TextInputType.numberWithOptions(decimal: true), + decoration: const InputDecoration( + hintText: 'Enter maxHeight if desired'), + ), + TextField( + controller: qualityController, + keyboardType: TextInputType.number, + decoration: const InputDecoration( + hintText: 'Enter quality if desired'), + ), + ], + ), + actions: [ + TextButton( + child: const Text('CANCEL'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + TextButton( + child: const Text('PICK'), + onPressed: () { + final double? width = maxWidthController.text.isNotEmpty + ? double.parse(maxWidthController.text) + : null; + final double? height = maxHeightController.text.isNotEmpty + ? double.parse(maxHeightController.text) + : null; + final int? quality = qualityController.text.isNotEmpty + ? int.parse(qualityController.text) + : null; + onPick(width, height, quality); + Navigator.of(context).pop(); + }), + ], + ); + }); + } + + void _showPickedSnackBar(BuildContext context, List files) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text('Picked: ${files.map((XFile it) => it.name).join(',')}'), + duration: const Duration(seconds: 2), + )); + } +} + +typedef OnPickImageCallback = void Function( + double? maxWidth, double? maxHeight, int? quality); + +class AspectRatioVideo extends StatefulWidget { + const AspectRatioVideo(this.controller, {super.key}); + + final VideoPlayerController? controller; + + @override + AspectRatioVideoState createState() => AspectRatioVideoState(); +} + +class AspectRatioVideoState extends State { + VideoPlayerController? get controller => widget.controller; + bool initialized = false; + + void _onVideoControllerUpdate() { + if (!mounted) { + return; + } + if (initialized != controller!.value.isInitialized) { + initialized = controller!.value.isInitialized; + setState(() {}); + } + } + + @override + void initState() { + super.initState(); + controller!.addListener(_onVideoControllerUpdate); + } + + @override + void dispose() { + controller!.removeListener(_onVideoControllerUpdate); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + if (initialized) { + return Center( + child: AspectRatio( + aspectRatio: controller!.value.aspectRatio, + child: VideoPlayer(controller!), + ), + ); + } else { + return Container(); + } + } +} + +T? _firstOrNull(List list) { + return list.isEmpty ? null : list.first; +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/CMakeLists.txt new file mode 100644 index 00000000..1fbfa727 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/CMakeLists.txt @@ -0,0 +1,138 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "example") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "dev.flutter.plugins.imagePickerExample") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/flutter/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/flutter/generated_plugins.cmake b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..2db3c22a --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/flutter/generated_plugins.cmake @@ -0,0 +1,24 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/main.cc b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/main.cc new file mode 100644 index 00000000..1507d028 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/main.cc @@ -0,0 +1,10 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/my_application.cc b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/my_application.cc new file mode 100644 index 00000000..3a67810f --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/my_application.cc @@ -0,0 +1,111 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "example"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments( + project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, + gchar*** arguments, + int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = + my_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, "flags", + G_APPLICATION_NON_UNIQUE, nullptr)); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/my_application.h b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/my_application.h new file mode 100644 index 00000000..6e9f0c3f --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/linux/my_application.h @@ -0,0 +1,22 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/pubspec.yaml b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/pubspec.yaml new file mode 100644 index 00000000..b1626f31 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/example/pubspec.yaml @@ -0,0 +1,29 @@ +name: example +description: Example for image_picker_linux implementation. +publish_to: 'none' +version: 1.0.0 + +environment: + sdk: ^3.6.0 + flutter: ">=3.27.0" + +dependencies: + flutter: + sdk: flutter + image_picker_linux: + # When depending on this package from a real application you should use: + # image_picker_linux: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. + path: .. + image_picker_platform_interface: ^2.11.0 + mime: ^2.0.0 + video_player: ^2.1.4 + +dev_dependencies: + flutter_test: + sdk: flutter + +flutter: + uses-material-design: true diff --git a/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/lib/image_picker_linux.dart b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/lib/image_picker_linux.dart new file mode 100644 index 00000000..deacebaf --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/lib/image_picker_linux.dart @@ -0,0 +1,193 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file_selector_linux/file_selector_linux.dart'; +import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; +import 'package:flutter/foundation.dart'; +import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; + +/// The Linux implementation of [ImagePickerPlatform]. +/// +/// This class implements the `package:image_picker` functionality for +/// Linux. +class ImagePickerLinux extends CameraDelegatingImagePickerPlatform { + /// Constructs a platform implementation. + ImagePickerLinux(); + + /// The file selector used to prompt the user to select images or videos. + @visibleForTesting + static FileSelectorPlatform fileSelector = FileSelectorLinux(); + + /// Registers this class as the default instance of [ImagePickerPlatform]. + static void registerWith() { + ImagePickerPlatform.instance = ImagePickerLinux(); + } + + // This is soft-deprecated in the platform interface, and is only implemented + // for compatibility. Callers should be using getImageFromSource. + @override + Future pickImage({ + required ImageSource source, + double? maxWidth, + double? maxHeight, + int? imageQuality, + CameraDevice preferredCameraDevice = CameraDevice.rear, + }) async { + final XFile? file = await getImageFromSource( + source: source, + options: ImagePickerOptions( + maxWidth: maxWidth, + maxHeight: maxHeight, + imageQuality: imageQuality, + preferredCameraDevice: preferredCameraDevice)); + if (file != null) { + return PickedFile(file.path); + } + return null; + } + + // This is soft-deprecated in the platform interface, and is only implemented + // for compatibility. Callers should be using getVideo. + @override + Future pickVideo({ + required ImageSource source, + CameraDevice preferredCameraDevice = CameraDevice.rear, + Duration? maxDuration, + }) async { + final XFile? file = await getVideo( + source: source, + preferredCameraDevice: preferredCameraDevice, + maxDuration: maxDuration); + if (file != null) { + return PickedFile(file.path); + } + return null; + } + + // This is soft-deprecated in the platform interface, and is only implemented + // for compatibility. Callers should be using getImageFromSource. + @override + Future getImage({ + required ImageSource source, + double? maxWidth, + double? maxHeight, + int? imageQuality, + CameraDevice preferredCameraDevice = CameraDevice.rear, + }) async { + return getImageFromSource( + source: source, + options: ImagePickerOptions( + maxWidth: maxWidth, + maxHeight: maxHeight, + imageQuality: imageQuality, + preferredCameraDevice: preferredCameraDevice)); + } + + // [ImagePickerOptions] options are not currently supported. If any + // of its fields are set, they will be silently ignored. + // + // If source is `ImageSource.camera`, a `StateError` will be thrown + // unless a [cameraDelegate] is set. + @override + Future getImageFromSource({ + required ImageSource source, + ImagePickerOptions options = const ImagePickerOptions(), + }) async { + switch (source) { + case ImageSource.camera: + return super.getImageFromSource(source: source); + case ImageSource.gallery: + const XTypeGroup typeGroup = + XTypeGroup(label: 'Images', mimeTypes: ['image/*']); + final XFile? file = await fileSelector + .openFile(acceptedTypeGroups: [typeGroup]); + return file; + } + // Ensure that there's a fallback in case a new source is added. + // ignore: dead_code + throw UnimplementedError('Unknown ImageSource: $source'); + } + + // `preferredCameraDevice` and `maxDuration` arguments are not currently + // supported. If either of these arguments are supplied, they will be silently + // ignored. + // + // If source is `ImageSource.camera`, a `StateError` will be thrown + // unless a [cameraDelegate] is set. + @override + Future getVideo({ + required ImageSource source, + CameraDevice preferredCameraDevice = CameraDevice.rear, + Duration? maxDuration, + }) async { + switch (source) { + case ImageSource.camera: + return super.getVideo( + source: source, + preferredCameraDevice: preferredCameraDevice, + maxDuration: maxDuration); + case ImageSource.gallery: + const XTypeGroup typeGroup = + XTypeGroup(label: 'Videos', mimeTypes: ['video/*']); + final XFile? file = await fileSelector + .openFile(acceptedTypeGroups: [typeGroup]); + return file; + } + // Ensure that there's a fallback in case a new source is added. + // ignore: dead_code + throw UnimplementedError('Unknown ImageSource: $source'); + } + + // `maxWidth`, `maxHeight`, and `imageQuality` arguments are not currently + // supported. If any of these arguments are supplied, they will be silently + // ignored. + @override + Future> getMultiImage({ + double? maxWidth, + double? maxHeight, + int? imageQuality, + }) async { + const XTypeGroup typeGroup = + XTypeGroup(label: 'Images', mimeTypes: ['image/*']); + final List files = await fileSelector + .openFiles(acceptedTypeGroups: [typeGroup]); + return files; + } + + @override + Future> getMultiVideoWithOptions( + {MultiVideoPickerOptions options = + const MultiVideoPickerOptions()}) async { + const XTypeGroup typeGroup = + XTypeGroup(label: 'Videos', mimeTypes: ['video/*']); + final List files = await fileSelector + .openFiles(acceptedTypeGroups: [typeGroup]); + return files; + } + + // `maxWidth`, `maxHeight`, and `imageQuality` arguments are not currently + // supported. If any of these arguments are supplied, they will be silently + // ignored. + @override + Future> getMedia({required MediaOptions options}) async { + const XTypeGroup typeGroup = XTypeGroup( + label: 'Images and videos', + mimeTypes: ['image/*', 'video/*'], + ); + + List files; + + if (options.allowMultiple) { + files = await fileSelector + .openFiles(acceptedTypeGroups: [typeGroup]); + } else { + final XFile? file = await fileSelector + .openFile(acceptedTypeGroups: [typeGroup]); + files = [ + if (file != null) file, + ]; + } + return files; + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/pubspec.yaml b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/pubspec.yaml new file mode 100644 index 00000000..ba1d4c4d --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux/pubspec.yaml @@ -0,0 +1,34 @@ +name: image_picker_linux +description: Linux platform implementation of image_picker +repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_linux +issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 +version: 0.2.2 + +environment: + sdk: ^3.6.0 + flutter: ">=3.27.0" + +flutter: + plugin: + implements: image_picker + platforms: + linux: + dartPluginClass: ImagePickerLinux + +dependencies: + file_selector_linux: ^0.9.1+3 + file_selector_platform_interface: ^2.2.0 + flutter: + sdk: flutter + image_picker_platform_interface: ^2.11.0 + +dev_dependencies: + build_runner: ^2.1.5 + flutter_test: + sdk: flutter + mockito: ^5.4.4 + +topics: + - image-picker + - files + - file-selection diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/AUTHORS b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/AUTHORS new file mode 100644 index 00000000..493a0b4e --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/AUTHORS @@ -0,0 +1,66 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +The Chromium Authors +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/CHANGELOG.md b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/CHANGELOG.md new file mode 100644 index 00000000..ace2dad7 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/CHANGELOG.md @@ -0,0 +1,109 @@ +## 2.2.1 + +* Adds pub topics to package metadata. +* Updates minimum supported SDK version to Flutter 3.7/Dart 2.19. + +## 2.2.0 + +* Adds getApplicationCachePath() for storing app-specific cache files. + +## 2.1.11 + +* Removes obsolete null checks on non-nullable values. +* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18. + +## 2.1.10 + +* Clarifies explanation of endorsement in README. +* Aligns Dart and Flutter SDK constraints. + +## 2.1.9 + +* Updates links for the merge of flutter/plugins into flutter/packages. + +## 2.1.8 + +* Adds compatibility with `xdg_directories` 1.0. +* Updates minimum Flutter version to 3.0. + +## 2.1.7 + +* Bumps ffi dependency to match path_provider_windows. + +## 2.1.6 + +* Fixes library_private_types_in_public_api, sort_child_properties_last and use_key_in_widget_constructors + lint warnings. + +## 2.1.5 + +* Removes dependency on `meta`. + +## 2.1.4 + +* Fixes `getApplicationSupportPath` handling of applications where the + application ID is not set. + +## 2.1.3 + +* Change getApplicationSupportPath from using executable name to application ID (if provided). + * If the executable name based directory exists, continue to use that so existing applications continue with the same behaviour. + +## 2.1.2 + +* Fixes link in README. + +## 2.1.1 + +* Removed obsolete `pluginClass: none` from pubpsec. + +## 2.1.0 + +* Now `getTemporaryPath` returns the value of the `TMPDIR` environment variable primarily. If `TMPDIR` is not set, `/tmp` is returned. + +## 2.0.2 + +* Updated installation instructions in README. + +## 2.0.1 + +* Add `implements` to pubspec.yaml. +* Add `registerWith` method to the main Dart class. + +## 2.0.0 + +* Migrate to null safety. + +## 0.1.1+3 + +* Update Flutter SDK constraint. + +## 0.1.1+2 + +* Log errors in the example when calls to the `path_provider` fail. + +## 0.1.1+1 + +* Check in linux/ directory for example/ + +## 0.1.1 - NOT PUBLISHED + +* Reverts changes on 0.1.0, which broke the tree. + +## 0.1.0 - NOT PUBLISHED + +* This release updates getApplicationSupportPath to use the application ID instead of the executable name. + * No migration is provided, so any older apps that were using this path will now have a different directory. + +## 0.0.1+2 + +* This release updates the example to depend on the endorsed plugin rather than relative path + +## 0.0.1+1 + +* This updates the readme and pubspec and example to reflect the endorsement of this implementation of `path_provider` + +## 0.0.1 + +* The initial implementation of path\_provider for Linux + * Implements getApplicationSupportPath, getApplicationDocumentsPath, getDownloadsPath, and getTemporaryPath diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/integration_test/path_provider_test.dart b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/integration_test/path_provider_test.dart new file mode 100644 index 00000000..3353f561 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/integration_test/path_provider_test.dart @@ -0,0 +1,66 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:path_provider_linux/path_provider_linux.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + testWidgets('getTemporaryDirectory', (WidgetTester tester) async { + final PathProviderLinux provider = PathProviderLinux(); + final String? result = await provider.getTemporaryPath(); + _verifySampleFile(result, 'temporaryDirectory'); + }); + + testWidgets('getDownloadDirectory', (WidgetTester tester) async { + if (!Platform.isLinux) { + return; + } + final PathProviderLinux provider = PathProviderLinux(); + final String? result = await provider.getDownloadsPath(); + _verifySampleFile(result, 'downloadDirectory'); + }); + + testWidgets('getApplicationDocumentsDirectory', (WidgetTester tester) async { + final PathProviderLinux provider = PathProviderLinux(); + final String? result = await provider.getApplicationDocumentsPath(); + _verifySampleFile(result, 'applicationDocuments'); + }); + + testWidgets('getApplicationSupportDirectory', (WidgetTester tester) async { + final PathProviderLinux provider = PathProviderLinux(); + final String? result = await provider.getApplicationSupportPath(); + _verifySampleFile(result, 'applicationSupport'); + }); + + testWidgets('getApplicationCacheDirectory', (WidgetTester tester) async { + final PathProviderLinux provider = PathProviderLinux(); + final String? result = await provider.getApplicationCachePath(); + _verifySampleFile(result, 'applicationCache'); + }); +} + +/// Verify a file called [name] in [directoryPath] by recreating it with test +/// contents when necessary. +void _verifySampleFile(String? directoryPath, String name) { + expect(directoryPath, isNotNull); + if (directoryPath == null) { + return; + } + final Directory directory = Directory(directoryPath); + final File file = File('${directory.path}${Platform.pathSeparator}$name'); + + if (file.existsSync()) { + file.deleteSync(); + expect(file.existsSync(), isFalse); + } + + file.writeAsStringSync('Hello world!'); + expect(file.readAsStringSync(), 'Hello world!'); + expect(directory.listSync(), isNotEmpty); + file.deleteSync(); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/lib/main.dart b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/lib/main.dart new file mode 100644 index 00000000..3cbb6915 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/lib/main.dart @@ -0,0 +1,109 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:path_provider_linux/path_provider_linux.dart'; + +void main() { + runApp(const MyApp()); +} + +/// Sample app +class MyApp extends StatefulWidget { + /// Default Constructor + const MyApp({super.key}); + + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + String? _tempDirectory = 'Unknown'; + String? _downloadsDirectory = 'Unknown'; + String? _appSupportDirectory = 'Unknown'; + String? _appCacheDirectory = 'Unknown'; + String? _documentsDirectory = 'Unknown'; + final PathProviderLinux _provider = PathProviderLinux(); + + @override + void initState() { + super.initState(); + initDirectories(); + } + + // Platform messages are asynchronous, so we initialize in an async method. + Future initDirectories() async { + String? tempDirectory; + String? downloadsDirectory; + String? appSupportDirectory; + String? appCacheDirectory; + String? documentsDirectory; + // Platform messages may fail, so we use a try/catch PlatformException. + try { + tempDirectory = await _provider.getTemporaryPath(); + } on PlatformException { + tempDirectory = 'Failed to get temp directory.'; + } + try { + downloadsDirectory = await _provider.getDownloadsPath(); + } on PlatformException { + downloadsDirectory = 'Failed to get downloads directory.'; + } + + try { + documentsDirectory = await _provider.getApplicationDocumentsPath(); + } on PlatformException { + documentsDirectory = 'Failed to get documents directory.'; + } + + try { + appSupportDirectory = await _provider.getApplicationSupportPath(); + } on PlatformException { + appSupportDirectory = 'Failed to get documents directory.'; + } + + try { + appCacheDirectory = await _provider.getApplicationCachePath(); + } on PlatformException { + appCacheDirectory = 'Failed to get cache directory.'; + } + // If the widget was removed from the tree while the asynchronous platform + // message was in flight, we want to discard the reply rather than calling + // setState to update our non-existent appearance. + if (!mounted) { + return; + } + + setState(() { + _tempDirectory = tempDirectory; + _downloadsDirectory = downloadsDirectory; + _appSupportDirectory = appSupportDirectory; + _appCacheDirectory = appCacheDirectory; + _documentsDirectory = documentsDirectory; + }); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Path Provider Linux example app'), + ), + body: Center( + child: Column( + children: [ + Text('Temp Directory: $_tempDirectory\n'), + Text('Documents Directory: $_documentsDirectory\n'), + Text('Downloads Directory: $_downloadsDirectory\n'), + Text('Application Support Directory: $_appSupportDirectory\n'), + Text('Application Cache Directory: $_appCacheDirectory\n'), + ], + ), + ), + ), + ); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/CMakeLists.txt new file mode 100644 index 00000000..4c422c77 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/CMakeLists.txt @@ -0,0 +1,106 @@ +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +set(BINARY_NAME "example") +set(APPLICATION_ID "dev.flutter.plugins.path_provider_linux_example") + +cmake_policy(SET CMP0063 NEW) + +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Application build +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) +apply_standard_settings(${BINARY_NAME}) +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +add_dependencies(${BINARY_NAME} flutter_assemble) +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/flutter/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..94f43ff7 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/flutter/CMakeLists.txt @@ -0,0 +1,86 @@ +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + linux-x64 ${CMAKE_BUILD_TYPE} +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/flutter/generated_plugins.cmake b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..2e1de87a --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/main.cc b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/main.cc new file mode 100644 index 00000000..88a5fd45 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/main.cc @@ -0,0 +1,15 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "my_application.h" + +int main(int argc, char** argv) { + // Only X11 is currently supported. + // Wayland support is being developed: + // https://github.com/flutter/flutter/issues/57932. + gdk_set_allowed_backends("x11"); + + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/my_application.cc b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/my_application.cc new file mode 100644 index 00000000..9cb411ba --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/my_application.cc @@ -0,0 +1,49 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "my_application.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new( + my_application_get_type(), "application-id", APPLICATION_ID, nullptr)); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/my_application.h b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/my_application.h new file mode 100644 index 00000000..6e9f0c3f --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/linux/my_application.h @@ -0,0 +1,22 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/pubspec.yaml b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/pubspec.yaml new file mode 100644 index 00000000..33fa8914 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/pubspec.yaml @@ -0,0 +1,28 @@ +name: pathproviderexample +description: Demonstrates how to use the path_provider_linux plugin. +publish_to: "none" + +environment: + sdk: ">=2.19.0 <4.0.0" + flutter: ">=3.7.0" + +dependencies: + flutter: + sdk: flutter + + path_provider_linux: + # When depending on this package from a real application you should use: + # path_provider_linux: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. + path: ../ + +dev_dependencies: + flutter_test: + sdk: flutter + integration_test: + sdk: flutter + +flutter: + uses-material-design: true diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/test_driver/integration_test.dart b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/test_driver/integration_test.dart new file mode 100644 index 00000000..4f10f2a5 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/test_driver/integration_test.dart @@ -0,0 +1,7 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/lib/path_provider_linux.dart b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/lib/path_provider_linux.dart new file mode 100644 index 00000000..e32af1bf --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/lib/path_provider_linux.dart @@ -0,0 +1,5 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +export 'src/path_provider_linux.dart'; diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/lib/src/get_application_id.dart b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/lib/src/get_application_id.dart new file mode 100644 index 00000000..e169c025 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/lib/src/get_application_id.dart @@ -0,0 +1,9 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// getApplicationId() is implemented using FFI; export a stub for platforms +// that don't support FFI (e.g., web) to avoid having transitive dependencies +// break web compilation. +export 'get_application_id_stub.dart' + if (dart.library.ffi) 'get_application_id_real.dart'; diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/lib/src/get_application_id_real.dart b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/lib/src/get_application_id_real.dart new file mode 100644 index 00000000..5e16df06 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/lib/src/get_application_id_real.dart @@ -0,0 +1,78 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ffi'; +import 'package:ffi/ffi.dart'; +import 'package:flutter/foundation.dart' show visibleForTesting; + +// GApplication* g_application_get_default(); +typedef _GApplicationGetDefaultC = IntPtr Function(); +typedef _GApplicationGetDefaultDart = int Function(); + +// const gchar* g_application_get_application_id(GApplication* application); +typedef _GApplicationGetApplicationIdC = Pointer Function(IntPtr); +typedef _GApplicationGetApplicationIdDart = Pointer Function(int); + +/// Interface for interacting with libgio. +@visibleForTesting +class GioUtils { + /// Creates a default instance that uses the real libgio. + GioUtils() { + try { + _gio = DynamicLibrary.open('libgio-2.0.so'); + } on ArgumentError { + _gio = null; + } + } + + DynamicLibrary? _gio; + + /// True if libgio was opened successfully. + bool get libraryIsPresent => _gio != null; + + /// Wraps `g_application_get_default`. + int gApplicationGetDefault() { + if (_gio == null) { + return 0; + } + final _GApplicationGetDefaultDart getDefault = _gio! + .lookupFunction<_GApplicationGetDefaultC, _GApplicationGetDefaultDart>( + 'g_application_get_default'); + return getDefault(); + } + + /// Wraps g_application_get_application_id. + Pointer gApplicationGetApplicationId(int app) { + if (_gio == null) { + return nullptr; + } + final _GApplicationGetApplicationIdDart gApplicationGetApplicationId = _gio! + .lookupFunction<_GApplicationGetApplicationIdC, + _GApplicationGetApplicationIdDart>( + 'g_application_get_application_id'); + return gApplicationGetApplicationId(app); + } +} + +/// Allows overriding the default GioUtils instance with a fake for testing. +@visibleForTesting +GioUtils? gioUtilsOverride; + +/// Gets the application ID for this app. +String? getApplicationId() { + final GioUtils gio = gioUtilsOverride ?? GioUtils(); + if (!gio.libraryIsPresent) { + return null; + } + + final int app = gio.gApplicationGetDefault(); + if (app == 0) { + return null; + } + final Pointer appId = gio.gApplicationGetApplicationId(app); + if (appId == nullptr) { + return null; + } + return appId.toDartString(); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/lib/src/get_application_id_stub.dart b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/lib/src/get_application_id_stub.dart new file mode 100644 index 00000000..90999769 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/lib/src/get_application_id_stub.dart @@ -0,0 +1,6 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// Gets the application ID for this app. +String? getApplicationId() => null; diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/lib/src/path_provider_linux.dart b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/lib/src/path_provider_linux.dart new file mode 100644 index 00000000..59097114 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/lib/src/path_provider_linux.dart @@ -0,0 +1,102 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:path/path.dart' as path; +import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; +import 'package:xdg_directories/xdg_directories.dart' as xdg; + +import 'get_application_id.dart'; + +/// The linux implementation of [PathProviderPlatform] +/// +/// This class implements the `package:path_provider` functionality for Linux. +class PathProviderLinux extends PathProviderPlatform { + /// Constructs an instance of [PathProviderLinux] + PathProviderLinux() : _environment = Platform.environment; + + /// Constructs an instance of [PathProviderLinux] with the given [environment] + @visibleForTesting + PathProviderLinux.private( + {Map environment = const {}, + String? executableName, + String? applicationId}) + : _environment = environment, + _executableName = executableName, + _applicationId = applicationId; + + final Map _environment; + String? _executableName; + String? _applicationId; + + /// Registers this class as the default instance of [PathProviderPlatform] + static void registerWith() { + PathProviderPlatform.instance = PathProviderLinux(); + } + + @override + Future getTemporaryPath() { + final String environmentTmpDir = _environment['TMPDIR'] ?? ''; + return Future.value( + environmentTmpDir.isEmpty ? '/tmp' : environmentTmpDir, + ); + } + + @override + Future getApplicationSupportPath() async { + final Directory directory = + Directory(path.join(xdg.dataHome.path, await _getId())); + if (directory.existsSync()) { + return directory.path; + } + + // This plugin originally used the executable name as a directory. + // Use that if it exists for backwards compatibility. + final Directory legacyDirectory = + Directory(path.join(xdg.dataHome.path, await _getExecutableName())); + if (legacyDirectory.existsSync()) { + return legacyDirectory.path; + } + + // Create the directory, because mobile implementations assume the directory exists. + await directory.create(recursive: true); + return directory.path; + } + + @override + Future getApplicationDocumentsPath() { + return Future.value(xdg.getUserDirectory('DOCUMENTS')?.path); + } + + @override + Future getApplicationCachePath() async { + final Directory directory = + Directory(path.join(xdg.cacheHome.path, await _getId())); + if (!directory.existsSync()) { + await directory.create(recursive: true); + } + return directory.path; + } + + @override + Future getDownloadsPath() { + return Future.value(xdg.getUserDirectory('DOWNLOAD')?.path); + } + + // Gets the name of this executable. + Future _getExecutableName() async { + _executableName ??= path.basenameWithoutExtension( + await File('/proc/self/exe').resolveSymbolicLinks()); + return _executableName!; + } + + // Gets the unique ID for this application. + Future _getId() async { + _applicationId ??= getApplicationId(); + // If no application ID then fall back to using the executable name. + return _applicationId ?? await _getExecutableName(); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/pubspec.yaml b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/pubspec.yaml new file mode 100644 index 00000000..4ad2805a --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/pubspec.yaml @@ -0,0 +1,33 @@ +name: path_provider_linux +description: Linux implementation of the path_provider plugin +repository: https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_linux +issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22 +version: 2.2.1 + +environment: + sdk: ">=2.19.0 <4.0.0" + flutter: ">=3.7.0" + +flutter: + plugin: + implements: path_provider + platforms: + linux: + dartPluginClass: PathProviderLinux + +dependencies: + ffi: ">=1.1.2 <3.0.0" + flutter: + sdk: flutter + path: ^1.8.0 + path_provider_platform_interface: ^2.1.0 + xdg_directories: ">=0.2.0 <2.0.0" + +dev_dependencies: + flutter_test: + sdk: flutter + +topics: + - files + - path-provider + - paths diff --git a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/AUTHORS b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/AUTHORS new file mode 100644 index 00000000..493a0b4e --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/AUTHORS @@ -0,0 +1,66 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +The Chromium Authors +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/CHANGELOG.md b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/CHANGELOG.md new file mode 100644 index 00000000..43c46f51 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/CHANGELOG.md @@ -0,0 +1,110 @@ +## 2.4.1 + +* Fixes `getStringList` returning immutable list. +* Fixes `getStringList` cast error. +* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. + +## 2.4.0 + +* Adds `SharedPreferencesAsyncLinux` API. +* Updates minimum supported SDK version to Flutter 3.16/Dart 3.2. + +## 2.3.2 + +* Updates `package:file` version constraints. + +## 2.3.1 + +* Adds pub topics to package metadata. +* Updates minimum supported SDK version to Flutter 3.7/Dart 2.19. + +## 2.3.0 + +* Adds `clearWithParameters` and `getAllWithParameters` methods. +* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18. + +## 2.2.0 + +* Adds `getAllWithPrefix` and `clearWithPrefix` methods. + +## 2.1.5 + +* Clarifies explanation of endorsement in README. +* Aligns Dart and Flutter SDK constraints. + +## 2.1.4 + +* Updates links for the merge of flutter/plugins into flutter/packages. +* Updates minimum Flutter version to 3.0. + +## 2.1.3 + +* Updates code for stricter lint checks. + +## 2.1.2 + +* Updates code for stricter lint checks. +* Updates code for `no_leading_underscores_for_local_identifiers` lint. +* Updates minimum Flutter version to 2.10. + +## 2.1.1 + +* Removes unnecessary imports. +* Fixes library_private_types_in_public_api, sort_child_properties_last and use_key_in_widget_constructors + lint warnings. + +## 2.1.0 + +* Deprecated `SharedPreferencesWindows.instance` in favor of `SharedPreferencesStorePlatform.instance`. + +## 2.0.4 + +* Removes dependency on `meta`. + +## 2.0.3 + +* Removed obsolete `pluginClass: none` from pubpsec. +* Fixes newly enabled analyzer options. + +## 2.0.2 + +* Updated installation instructions in README. + +## 2.0.1 + +* Add `implements` to the pubspec. +* Add `registerWith` to the Dart main class. + +## 2.0.0 + +* Migrate to null-safety. + +## 0.0.3+1 + +* Update Flutter SDK constraint. + +## 0.0.3 + +* Update integration test examples to use `testWidgets` instead of `test`. + +## 0.0.2+4 + +* Remove unused `test` dependency. +* Update Dart SDK constraint in example. + +## 0.0.2+3 + +* Check in linux/ directory for example/ + +## 0.0.2+2 + +* Bump the `file` package dependency to resolve dep conflicts with `flutter_driver`. + +## 0.0.2+1 +* Replace path_provider dependency with path_provider_linux. + +## 0.0.2 +* Add iOS stub. + +## 0.0.1 +* Initial release to support shared_preferences on Linux. diff --git a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/integration_test/shared_preferences_test.dart b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/integration_test/shared_preferences_test.dart new file mode 100644 index 00000000..fdabea41 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/integration_test/shared_preferences_test.dart @@ -0,0 +1,556 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:shared_preferences_linux/shared_preferences_linux.dart'; +import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart'; +import 'package:shared_preferences_platform_interface/types.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + group('SharedPreferencesLinux', () { + late SharedPreferencesLinux preferences; + + const Map flutterTestValues = { + 'flutter.String': 'hello world', + 'flutter.Bool': true, + 'flutter.Int': 42, + 'flutter.Double': 3.14159, + 'flutter.StringList': ['foo', 'bar'], + }; + + const Map prefixTestValues = { + 'prefix.String': 'hello world', + 'prefix.Bool': true, + 'prefix.Int': 42, + 'prefix.Double': 3.14159, + 'prefix.StringList': ['foo', 'bar'], + }; + + const Map nonPrefixTestValues = { + 'String': 'hello world', + 'Bool': true, + 'Int': 42, + 'Double': 3.14159, + 'StringList': ['foo', 'bar'], + }; + + final Map allTestValues = {}; + + allTestValues.addAll(flutterTestValues); + allTestValues.addAll(prefixTestValues); + allTestValues.addAll(nonPrefixTestValues); + + Future addData() async { + await preferences.setValue('String', 'String', allTestValues['String']!); + await preferences.setValue('Bool', 'Bool', allTestValues['Bool']!); + await preferences.setValue('Int', 'Int', allTestValues['Int']!); + await preferences.setValue('Double', 'Double', allTestValues['Double']!); + await preferences.setValue( + 'StringList', 'StringList', allTestValues['StringList']!); + await preferences.setValue( + 'String', 'prefix.String', allTestValues['prefix.String']!); + await preferences.setValue( + 'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!); + await preferences.setValue( + 'Int', 'prefix.Int', allTestValues['prefix.Int']!); + await preferences.setValue( + 'Double', 'prefix.Double', allTestValues['prefix.Double']!); + await preferences.setValue('StringList', 'prefix.StringList', + allTestValues['prefix.StringList']!); + await preferences.setValue( + 'String', 'flutter.String', allTestValues['flutter.String']!); + await preferences.setValue( + 'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!); + await preferences.setValue( + 'Int', 'flutter.Int', allTestValues['flutter.Int']!); + await preferences.setValue( + 'Double', 'flutter.Double', allTestValues['flutter.Double']!); + await preferences.setValue('StringList', 'flutter.StringList', + allTestValues['flutter.StringList']!); + } + + setUp(() async { + preferences = SharedPreferencesLinux(); + await addData(); + }); + + tearDown(() async { + await preferences.clearWithParameters( + ClearParameters( + filter: PreferencesFilter(prefix: ''), + ), + ); + }); + + testWidgets('getAll', (WidgetTester _) async { + final Map values = await preferences.getAll(); + expect(values['flutter.String'], allTestValues['flutter.String']); + expect(values['flutter.Bool'], allTestValues['flutter.Bool']); + expect(values['flutter.Int'], allTestValues['flutter.Int']); + expect(values['flutter.Double'], allTestValues['flutter.Double']); + expect(values['flutter.StringList'], allTestValues['flutter.StringList']); + }); + + group('withPrefix', () { + testWidgets('remove', (WidgetTester _) async { + const String key = 'flutter.String'; + await preferences.remove(key); + final Map values = + await preferences.getAllWithPrefix(''); + expect(values[key], isNull); + }); + + testWidgets('clear', (WidgetTester _) async { + await preferences.clear(); + final Map values = await preferences.getAll(); + expect(values['flutter.String'], null); + expect(values['flutter.Bool'], null); + expect(values['flutter.Int'], null); + expect(values['flutter.Double'], null); + expect(values['flutter.StringList'], null); + }); + + testWidgets('get all with prefix', (WidgetTester _) async { + final Map values = + await preferences.getAllWithPrefix('prefix.'); + expect(values['prefix.String'], allTestValues['prefix.String']); + expect(values['prefix.Bool'], allTestValues['prefix.Bool']); + expect(values['prefix.Int'], allTestValues['prefix.Int']); + expect(values['prefix.Double'], allTestValues['prefix.Double']); + expect(values['prefix.StringList'], allTestValues['prefix.StringList']); + }); + + testWidgets('getAllWithNoPrefix', (WidgetTester _) async { + final Map values = + await preferences.getAllWithPrefix(''); + expect(values['String'], allTestValues['String']); + expect(values['Bool'], allTestValues['Bool']); + expect(values['Int'], allTestValues['Int']); + expect(values['Double'], allTestValues['Double']); + expect(values['StringList'], allTestValues['StringList']); + expect(values['flutter.String'], allTestValues['flutter.String']); + expect(values['flutter.Bool'], allTestValues['flutter.Bool']); + expect(values['flutter.Int'], allTestValues['flutter.Int']); + expect(values['flutter.Double'], allTestValues['flutter.Double']); + expect( + values['flutter.StringList'], allTestValues['flutter.StringList']); + }); + + testWidgets('clearWithPrefix', (WidgetTester _) async { + await preferences.clearWithPrefix('prefix.'); + Map values = + await preferences.getAllWithPrefix('prefix.'); + expect(values['prefix.String'], null); + expect(values['prefix.Bool'], null); + expect(values['prefix.Int'], null); + expect(values['prefix.Double'], null); + expect(values['prefix.StringList'], null); + values = await preferences.getAllWithPrefix('flutter.'); + expect(values['flutter.String'], allTestValues['flutter.String']); + expect(values['flutter.Bool'], allTestValues['flutter.Bool']); + expect(values['flutter.Int'], allTestValues['flutter.Int']); + expect(values['flutter.Double'], allTestValues['flutter.Double']); + expect( + values['flutter.StringList'], allTestValues['flutter.StringList']); + }); + + testWidgets('clearWithNoPrefix', (WidgetTester _) async { + await preferences.clearWithPrefix(''); + final Map values = + await preferences.getAllWithPrefix(''); + expect(values['String'], null); + expect(values['Bool'], null); + expect(values['Int'], null); + expect(values['Double'], null); + expect(values['StringList'], null); + expect(values['flutter.String'], null); + expect(values['flutter.Bool'], null); + expect(values['flutter.Int'], null); + expect(values['flutter.Double'], null); + expect(values['flutter.StringList'], null); + }); + }); + + group('withParameters', () { + testWidgets('remove', (WidgetTester _) async { + const String key = 'flutter.String'; + await preferences.remove(key); + final Map values = + await preferences.getAllWithParameters( + GetAllParameters( + filter: PreferencesFilter(prefix: ''), + ), + ); + expect(values[key], isNull); + }); + + testWidgets('clear', (WidgetTester _) async { + await preferences.clear(); + final Map values = await preferences.getAll(); + expect(values['flutter.String'], null); + expect(values['flutter.Bool'], null); + expect(values['flutter.Int'], null); + expect(values['flutter.Double'], null); + expect(values['flutter.StringList'], null); + }); + + testWidgets('get all with prefix', (WidgetTester _) async { + final Map values = + await preferences.getAllWithParameters( + GetAllParameters( + filter: PreferencesFilter(prefix: 'prefix.'), + ), + ); + expect(values['prefix.String'], allTestValues['prefix.String']); + expect(values['prefix.Bool'], allTestValues['prefix.Bool']); + expect(values['prefix.Int'], allTestValues['prefix.Int']); + expect(values['prefix.Double'], allTestValues['prefix.Double']); + expect(values['prefix.StringList'], allTestValues['prefix.StringList']); + }); + + testWidgets('get all with allow list', (WidgetTester _) async { + final Map values = + await preferences.getAllWithParameters( + GetAllParameters( + filter: PreferencesFilter( + prefix: 'prefix.', + allowList: {'prefix.String'}, + ), + ), + ); + expect(values['prefix.String'], allTestValues['prefix.String']); + expect(values['prefix.Bool'], null); + expect(values['prefix.Int'], null); + expect(values['prefix.Double'], null); + expect(values['prefix.StringList'], null); + }); + + testWidgets('getAllWithNoPrefix', (WidgetTester _) async { + final Map values = + await preferences.getAllWithParameters( + GetAllParameters( + filter: PreferencesFilter(prefix: ''), + ), + ); + expect(values['String'], allTestValues['String']); + expect(values['Bool'], allTestValues['Bool']); + expect(values['Int'], allTestValues['Int']); + expect(values['Double'], allTestValues['Double']); + expect(values['StringList'], allTestValues['StringList']); + expect(values['flutter.String'], allTestValues['flutter.String']); + expect(values['flutter.Bool'], allTestValues['flutter.Bool']); + expect(values['flutter.Int'], allTestValues['flutter.Int']); + expect(values['flutter.Double'], allTestValues['flutter.Double']); + expect( + values['flutter.StringList'], allTestValues['flutter.StringList']); + }); + + testWidgets('clearWithParameters', (WidgetTester _) async { + await preferences.clearWithParameters( + ClearParameters( + filter: PreferencesFilter(prefix: 'prefix.'), + ), + ); + Map values = await preferences.getAllWithParameters( + GetAllParameters( + filter: PreferencesFilter(prefix: 'prefix.'), + ), + ); + expect(values['prefix.String'], null); + expect(values['prefix.Bool'], null); + expect(values['prefix.Int'], null); + expect(values['prefix.Double'], null); + expect(values['prefix.StringList'], null); + values = await preferences.getAllWithParameters( + GetAllParameters( + filter: PreferencesFilter(prefix: 'flutter.'), + ), + ); + expect(values['flutter.String'], allTestValues['flutter.String']); + expect(values['flutter.Bool'], allTestValues['flutter.Bool']); + expect(values['flutter.Int'], allTestValues['flutter.Int']); + expect(values['flutter.Double'], allTestValues['flutter.Double']); + expect( + values['flutter.StringList'], allTestValues['flutter.StringList']); + }); + + testWidgets('clearWithParameters with allow list', + (WidgetTester _) async { + await addData(); + await preferences.clearWithParameters( + ClearParameters( + filter: PreferencesFilter( + prefix: 'prefix.', + allowList: {'prefix.StringList'}, + ), + ), + ); + Map values = await preferences.getAllWithParameters( + GetAllParameters( + filter: PreferencesFilter(prefix: 'prefix.'), + ), + ); + expect(values['prefix.String'], allTestValues['prefix.String']); + expect(values['prefix.Bool'], allTestValues['prefix.Bool']); + expect(values['prefix.Int'], allTestValues['prefix.Int']); + expect(values['prefix.Double'], allTestValues['prefix.Double']); + expect(values['prefix.StringList'], null); + values = await preferences.getAllWithParameters( + GetAllParameters( + filter: PreferencesFilter(prefix: 'flutter.'), + ), + ); + expect(values['flutter.String'], allTestValues['flutter.String']); + expect(values['flutter.Bool'], allTestValues['flutter.Bool']); + expect(values['flutter.Int'], allTestValues['flutter.Int']); + expect(values['flutter.Double'], allTestValues['flutter.Double']); + expect( + values['flutter.StringList'], allTestValues['flutter.StringList']); + }); + + testWidgets('clearWithNoPrefix', (WidgetTester _) async { + await preferences.clearWithParameters( + ClearParameters( + filter: PreferencesFilter(prefix: ''), + ), + ); + final Map values = + await preferences.getAllWithParameters( + GetAllParameters( + filter: PreferencesFilter(prefix: ''), + ), + ); + expect(values['String'], null); + expect(values['Bool'], null); + expect(values['Int'], null); + expect(values['Double'], null); + expect(values['StringList'], null); + expect(values['flutter.String'], null); + expect(values['flutter.Bool'], null); + expect(values['flutter.Int'], null); + expect(values['flutter.Double'], null); + expect(values['flutter.StringList'], null); + }); + }); + }); + + group('shared_preferences_async', () { + const SharedPreferencesLinuxOptions emptyOptions = + SharedPreferencesLinuxOptions(); + + const String stringKey = 'testString'; + const String boolKey = 'testBool'; + const String intKey = 'testInt'; + const String doubleKey = 'testDouble'; + const String listKey = 'testList'; + + const String testString = 'hello world'; + const bool testBool = true; + const int testInt = 42; + const double testDouble = 3.14159; + const List testList = ['foo', 'bar']; + + Future getPreferences( + {bool clear = true}) async { + final SharedPreferencesAsyncPlatform preferences = + SharedPreferencesAsyncPlatform.instance!; + if (clear) { + await preferences.clear( + const ClearPreferencesParameters(filter: PreferencesFilters()), + emptyOptions); + } + return preferences; + } + + testWidgets('set and get String', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + + await preferences.setString(stringKey, testString, emptyOptions); + expect(await preferences.getString(stringKey, emptyOptions), testString); + }); + + testWidgets('set and get bool', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + + await preferences.setBool(boolKey, testBool, emptyOptions); + expect(await preferences.getBool(boolKey, emptyOptions), testBool); + }); + + testWidgets('set and get int', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + + await preferences.setInt(intKey, testInt, emptyOptions); + expect(await preferences.getInt(intKey, emptyOptions), testInt); + }); + + testWidgets('set and get double', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + + await preferences.setDouble(doubleKey, testDouble, emptyOptions); + expect(await preferences.getDouble(doubleKey, emptyOptions), testDouble); + }); + + testWidgets('set and get StringList', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + + await preferences.setStringList(listKey, testList, emptyOptions); + expect(await preferences.getStringList(listKey, emptyOptions), testList); + }); + testWidgets('getStringList does not throw cast error', + (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + + await preferences.setStringList(listKey, testList, emptyOptions); + await (preferences as SharedPreferencesAsyncLinux).reload(emptyOptions); + expect(await preferences.getStringList(listKey, emptyOptions), testList); + }); + + testWidgets('getStringList returns mutable list', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + + await preferences.setStringList(listKey, testList, emptyOptions); + final List? list = + await preferences.getStringList(listKey, emptyOptions); + list?.add('value'); + expect(list?.length, testList.length + 1); + }); + + testWidgets('getPreferences', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + await Future.wait(>[ + preferences.setString(stringKey, testString, emptyOptions), + preferences.setBool(boolKey, testBool, emptyOptions), + preferences.setInt(intKey, testInt, emptyOptions), + preferences.setDouble(doubleKey, testDouble, emptyOptions), + preferences.setStringList(listKey, testList, emptyOptions) + ]); + + final Map gotAll = await preferences.getPreferences( + const GetPreferencesParameters(filter: PreferencesFilters()), + emptyOptions, + ); + + expect(gotAll.length, 5); + expect(gotAll[stringKey], testString); + expect(gotAll[boolKey], testBool); + expect(gotAll[intKey], testInt); + expect(gotAll[doubleKey], testDouble); + expect(gotAll[listKey], testList); + }); + + testWidgets('getPreferences with filter', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + await Future.wait(>[ + preferences.setString(stringKey, testString, emptyOptions), + preferences.setBool(boolKey, testBool, emptyOptions), + preferences.setInt(intKey, testInt, emptyOptions), + preferences.setDouble(doubleKey, testDouble, emptyOptions), + preferences.setStringList(listKey, testList, emptyOptions) + ]); + + final Map gotAll = await preferences.getPreferences( + const GetPreferencesParameters( + filter: PreferencesFilters(allowList: {stringKey, boolKey}), + ), + emptyOptions, + ); + + expect(gotAll.length, 2); + expect(gotAll[stringKey], testString); + expect(gotAll[boolKey], testBool); + }); + + testWidgets('getKeys', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + await Future.wait(>[ + preferences.setString(stringKey, testString, emptyOptions), + preferences.setBool(boolKey, testBool, emptyOptions), + preferences.setInt(intKey, testInt, emptyOptions), + preferences.setDouble(doubleKey, testDouble, emptyOptions), + preferences.setStringList(listKey, testList, emptyOptions) + ]); + + final Set keys = await preferences.getKeys( + const GetPreferencesParameters(filter: PreferencesFilters()), + emptyOptions, + ); + + expect(keys.length, 5); + expect(keys, contains(stringKey)); + expect(keys, contains(boolKey)); + expect(keys, contains(intKey)); + expect(keys, contains(doubleKey)); + expect(keys, contains(listKey)); + }); + + testWidgets('getKeys with filter', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + await Future.wait(>[ + preferences.setString(stringKey, testString, emptyOptions), + preferences.setBool(boolKey, testBool, emptyOptions), + preferences.setInt(intKey, testInt, emptyOptions), + preferences.setDouble(doubleKey, testDouble, emptyOptions), + preferences.setStringList(listKey, testList, emptyOptions) + ]); + + final Set keys = await preferences.getKeys( + const GetPreferencesParameters( + filter: PreferencesFilters(allowList: {stringKey, boolKey}), + ), + emptyOptions, + ); + + expect(keys.length, 2); + expect(keys, contains(stringKey)); + expect(keys, contains(boolKey)); + }); + + testWidgets('clear', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + await Future.wait(>[ + preferences.setString(stringKey, testString, emptyOptions), + preferences.setBool(boolKey, testBool, emptyOptions), + preferences.setInt(intKey, testInt, emptyOptions), + preferences.setDouble(doubleKey, testDouble, emptyOptions), + preferences.setStringList(listKey, testList, emptyOptions) + ]); + + await preferences.clear( + const ClearPreferencesParameters(filter: PreferencesFilters()), + emptyOptions, + ); + + expect(await preferences.getString(stringKey, emptyOptions), null); + expect(await preferences.getBool(boolKey, emptyOptions), null); + expect(await preferences.getInt(intKey, emptyOptions), null); + expect(await preferences.getDouble(doubleKey, emptyOptions), null); + expect(await preferences.getStringList(listKey, emptyOptions), null); + }); + + testWidgets('clear with filter', (WidgetTester _) async { + final SharedPreferencesAsyncPlatform preferences = await getPreferences(); + await Future.wait(>[ + preferences.setString(stringKey, testString, emptyOptions), + preferences.setBool(boolKey, testBool, emptyOptions), + preferences.setInt(intKey, testInt, emptyOptions), + preferences.setDouble(doubleKey, testDouble, emptyOptions), + preferences.setStringList(listKey, testList, emptyOptions) + ]); + await preferences.clear( + const ClearPreferencesParameters( + filter: PreferencesFilters(allowList: {stringKey, boolKey}), + ), + emptyOptions, + ); + expect(await preferences.getString(stringKey, emptyOptions), null); + expect(await preferences.getBool(boolKey, emptyOptions), null); + expect(await preferences.getInt(intKey, emptyOptions), testInt); + expect(await preferences.getDouble(doubleKey, emptyOptions), testDouble); + expect(await preferences.getStringList(listKey, emptyOptions), testList); + }); + }); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/lib/main.dart b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/lib/main.dart new file mode 100644 index 00000000..b333716c --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/lib/main.dart @@ -0,0 +1,100 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:shared_preferences_linux/shared_preferences_linux.dart'; +import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return const MaterialApp( + title: 'SharedPreferences Demo', + home: SharedPreferencesDemo(), + ); + } +} + +class SharedPreferencesDemo extends StatefulWidget { + const SharedPreferencesDemo({super.key}); + + @override + SharedPreferencesDemoState createState() => SharedPreferencesDemoState(); +} + +class SharedPreferencesDemoState extends State { + final SharedPreferencesAsyncPlatform? _prefs = + SharedPreferencesAsyncPlatform.instance; + final SharedPreferencesLinuxOptions options = + const SharedPreferencesLinuxOptions(); + static const String _counterKey = 'counter'; + late Future _counter; + + Future _incrementCounter() async { + final int? value = await _prefs!.getInt(_counterKey, options); + final int counter = (value ?? 0) + 1; + + setState(() { + _counter = _prefs.setInt(_counterKey, counter, options).then((_) { + return counter; + }); + }); + } + + Future _getAndSetCounter() async { + setState(() { + _counter = _prefs!.getInt(_counterKey, options).then((int? counter) { + return counter ?? 0; + }); + }); + } + + @override + void initState() { + super.initState(); + _getAndSetCounter(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('SharedPreferences Demo'), + ), + body: Center( + child: FutureBuilder( + future: _counter, + builder: (BuildContext context, AsyncSnapshot snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.none: + case ConnectionState.waiting: + return const CircularProgressIndicator(); + case ConnectionState.active: + case ConnectionState.done: + if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + return Text( + 'Button tapped ${snapshot.data} time${snapshot.data == 1 ? '' : 's'}.\n\n' + 'This should persist across restarts.', + ); + } + } + })), + floatingActionButton: FloatingActionButton( + onPressed: _incrementCounter, + tooltip: 'Increment', + child: const Icon(Icons.add), + ), + ); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/CMakeLists.txt new file mode 100644 index 00000000..0236a880 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/CMakeLists.txt @@ -0,0 +1,95 @@ +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +set(BINARY_NAME "example") + +cmake_policy(SET CMP0063 NEW) + +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) +apply_standard_settings(${BINARY_NAME}) +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/flutter/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..94f43ff7 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/flutter/CMakeLists.txt @@ -0,0 +1,86 @@ +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + linux-x64 ${CMAKE_BUILD_TYPE} +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/flutter/generated_plugins.cmake b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..2e1de87a --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/main.cc b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/main.cc new file mode 100644 index 00000000..1507d028 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/main.cc @@ -0,0 +1,10 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/my_application.cc b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/my_application.cc new file mode 100644 index 00000000..878cd973 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/my_application.cc @@ -0,0 +1,48 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "my_application.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), nullptr)); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/my_application.h b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/my_application.h new file mode 100644 index 00000000..6e9f0c3f --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/linux/my_application.h @@ -0,0 +1,22 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/pubspec.yaml b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/pubspec.yaml new file mode 100644 index 00000000..35da7cfa --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/pubspec.yaml @@ -0,0 +1,28 @@ +name: shared_preferences_linux_example +description: Demonstrates how to use the shared_preferences_linux plugin. +publish_to: none + +environment: + sdk: ^3.3.0 + flutter: ">=3.19.0" + +dependencies: + flutter: + sdk: flutter + shared_preferences_linux: + # When depending on this package from a real application you should use: + # shared_preferences_linux: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. + path: ../ + shared_preferences_platform_interface: ^2.4.0 + +dev_dependencies: + flutter_test: + sdk: flutter + integration_test: + sdk: flutter + +flutter: + uses-material-design: true diff --git a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/test_driver/integration_test.dart b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/test_driver/integration_test.dart new file mode 100644 index 00000000..4f10f2a5 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/example/test_driver/integration_test.dart @@ -0,0 +1,7 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/lib/shared_preferences_linux.dart b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/lib/shared_preferences_linux.dart new file mode 100644 index 00000000..d4ede84e --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/lib/shared_preferences_linux.dart @@ -0,0 +1,420 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:convert' show json; + +import 'package:file/file.dart'; +import 'package:file/local.dart'; +import 'package:flutter/foundation.dart' show debugPrint, visibleForTesting; +import 'package:path/path.dart' as path; +import 'package:path_provider_linux/path_provider_linux.dart'; +import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart'; +import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; +import 'package:shared_preferences_platform_interface/types.dart'; + +const String _defaultFileName = 'shared_preferences'; + +const String _defaultPrefix = 'flutter.'; + +/// The Linux implementation of [SharedPreferencesStorePlatform]. +/// +/// This class implements the `package:shared_preferences` functionality for Linux. +class SharedPreferencesLinux extends SharedPreferencesStorePlatform { + /// Deprecated instance of [SharedPreferencesLinux]. + /// Use [SharedPreferencesStorePlatform.instance] instead. + @Deprecated('Use `SharedPreferencesStorePlatform.instance` instead.') + static SharedPreferencesLinux instance = SharedPreferencesLinux(); + + /// Registers the Linux implementation. + static void registerWith() { + SharedPreferencesStorePlatform.instance = SharedPreferencesLinux(); + // A temporary work-around for having two plugins contained in a single package. + SharedPreferencesAsyncLinux.registerWith(); + } + + /// Local copy of preferences + Map? _cachedPreferences; + + /// File system used to store to disk. Exposed for testing only. + @visibleForTesting + FileSystem fs = const LocalFileSystem(); + + /// The path_provider_linux instance used to find the support directory. + @visibleForTesting + PathProviderLinux pathProvider = PathProviderLinux(); + + /// Checks for cached preferences and returns them or loads preferences from + /// file and returns and caches them. + Future> _readPreferences() async { + _cachedPreferences ??= await _reload( + _defaultFileName, + fs: fs, + pathProvider: pathProvider, + ); + return _cachedPreferences!; + } + + @override + Future clear() async { + return clearWithParameters( + ClearParameters( + filter: PreferencesFilter(prefix: _defaultPrefix), + ), + ); + } + + @override + Future clearWithPrefix(String prefix) async { + return clearWithParameters( + ClearParameters(filter: PreferencesFilter(prefix: prefix))); + } + + @override + Future clearWithParameters(ClearParameters parameters) async { + final PreferencesFilter filter = parameters.filter; + + final Map preferences = await _readPreferences(); + preferences.removeWhere((String key, _) => + key.startsWith(filter.prefix) && + (filter.allowList == null || filter.allowList!.contains(key))); + return _writePreferences( + preferences, + _defaultFileName, + fs: fs, + pathProvider: pathProvider, + ); + } + + @override + Future> getAll() async { + return getAllWithParameters( + GetAllParameters( + filter: PreferencesFilter(prefix: _defaultPrefix), + ), + ); + } + + @override + Future> getAllWithPrefix(String prefix) async { + return getAllWithParameters( + GetAllParameters(filter: PreferencesFilter(prefix: prefix))); + } + + @override + Future> getAllWithParameters( + GetAllParameters parameters) async { + final PreferencesFilter filter = parameters.filter; + final Map withPrefix = + Map.from(await _readPreferences()); + withPrefix.removeWhere((String key, _) => !(key.startsWith(filter.prefix) && + (filter.allowList?.contains(key) ?? true))); + return withPrefix; + } + + @override + Future remove(String key) async { + final Map preferences = await _readPreferences(); + preferences.remove(key); + return _writePreferences( + preferences, + _defaultFileName, + fs: fs, + pathProvider: pathProvider, + ); + } + + @override + Future setValue(String valueType, String key, Object value) async { + final Map preferences = await _readPreferences(); + preferences[key] = value; + return _writePreferences( + preferences, + _defaultFileName, + fs: fs, + pathProvider: pathProvider, + ); + } +} + +/// The Linux implementation of [SharedPreferencesAsyncPlatform]. +/// +/// This class implements the `package:shared_preferences` functionality for Linux. +base class SharedPreferencesAsyncLinux extends SharedPreferencesAsyncPlatform { + /// Registers the Linux implementation. + static void registerWith() { + SharedPreferencesAsyncPlatform.instance = SharedPreferencesAsyncLinux(); + } + + /// Local copy of preferences + Map? _cachedPreferences; + + /// File system used to store to disk. Exposed for testing only. + @visibleForTesting + FileSystem fs = const LocalFileSystem(); + + /// The path_provider_linux instance used to find the support directory. + @visibleForTesting + PathProviderLinux pathProvider = PathProviderLinux(); + + @override + Future> getKeys( + GetPreferencesParameters parameters, + SharedPreferencesOptions options, + ) async { + return (await getPreferences(parameters, options)).keys.toSet(); + } + + @override + Future setString( + String key, + String value, + SharedPreferencesOptions options, + ) { + return _setValue(key, value, options); + } + + @override + Future setBool( + String key, + bool value, + SharedPreferencesOptions options, + ) { + return _setValue(key, value, options); + } + + @override + Future setDouble( + String key, + double value, + SharedPreferencesOptions options, + ) { + return _setValue(key, value, options); + } + + @override + Future setInt( + String key, + int value, + SharedPreferencesOptions options, + ) { + return _setValue(key, value, options); + } + + @override + Future setStringList( + String key, + List value, + SharedPreferencesOptions options, + ) { + return _setValue(key, value, options); + } + + @override + Future getString( + String key, + SharedPreferencesOptions options, + ) async { + final Map data = await _readAll({key}, options); + return data[key] as String?; + } + + @override + Future getBool( + String key, + SharedPreferencesOptions options, + ) async { + final Map data = await _readAll({key}, options); + return data[key] as bool?; + } + + @override + Future getDouble( + String key, + SharedPreferencesOptions options, + ) async { + final Map data = await _readAll({key}, options); + return data[key] as double?; + } + + @override + Future getInt( + String key, + SharedPreferencesOptions options, + ) async { + final Map data = await _readAll({key}, options); + return data[key] as int?; + } + + @override + Future?> getStringList( + String key, + SharedPreferencesOptions options, + ) async { + final Map data = await _readAll({key}, options); + return (data[key] as List?)?.cast().toList(); + } + + @override + Future clear(ClearPreferencesParameters parameters, + SharedPreferencesOptions options) async { + final SharedPreferencesLinuxOptions linuxOptions = + SharedPreferencesLinuxOptions.fromSharedPreferencesOptions(options); + final PreferencesFilters filter = parameters.filter; + final Map preferences = + await _readPreferences(linuxOptions.fileName); + preferences.removeWhere((String key, _) => + filter.allowList == null || filter.allowList!.contains(key)); + await _writePreferences( + preferences, + linuxOptions.fileName, + fs: fs, + pathProvider: pathProvider, + ); + } + + @override + Future> getPreferences( + GetPreferencesParameters parameters, + SharedPreferencesOptions options, + ) async { + return _readAll(parameters.filter.allowList, options); + } + + /// Reloads preferences from file. + @visibleForTesting + Future reload( + SharedPreferencesLinuxOptions options, + ) async { + _cachedPreferences = await _reload(options.fileName); + } + + Future> _readAll( + Set? allowList, + SharedPreferencesOptions options, + ) async { + final SharedPreferencesLinuxOptions linuxOptions = + SharedPreferencesLinuxOptions.fromSharedPreferencesOptions(options); + final Map prefs = + Map.from(await _readPreferences(linuxOptions.fileName)); + prefs.removeWhere((String key, _) => !(allowList?.contains(key) ?? true)); + return prefs; + } + + Future _setValue( + String key, Object value, SharedPreferencesOptions options) async { + final SharedPreferencesLinuxOptions linuxOptions = + SharedPreferencesLinuxOptions.fromSharedPreferencesOptions(options); + final Map preferences = + await _readPreferences(linuxOptions.fileName); + preferences[key] = value; + await _writePreferences( + preferences, + linuxOptions.fileName, + fs: fs, + pathProvider: pathProvider, + ); + } + + /// Checks for cached preferences and returns them or loads preferences from + /// file and returns and caches them. + Future> _readPreferences(String fileName) async { + _cachedPreferences ??= await _reload( + fileName, + fs: fs, + pathProvider: pathProvider, + ); + return _cachedPreferences!; + } +} + +/// Gets the file where the preferences are stored. +Future _getLocalDataFile( + String fileName, { + FileSystem fs = const LocalFileSystem(), + PathProviderLinux? pathProvider, +}) async { + pathProvider = pathProvider ?? PathProviderLinux(); + final String? directory = await pathProvider.getApplicationSupportPath(); + if (directory == null) { + return null; + } + final String fileLocation = path.join(directory, '$fileName.json'); + return fs.file(fileLocation); +} + +/// Gets the preferences from the stored file and saves them in cache. +Future> _reload( + String fileName, { + FileSystem fs = const LocalFileSystem(), + PathProviderLinux? pathProvider, +}) async { + Map preferences = {}; + final File? localDataFile = await _getLocalDataFile( + fileName, + fs: fs, + pathProvider: pathProvider, + ); + if (localDataFile != null && localDataFile.existsSync()) { + final String stringMap = localDataFile.readAsStringSync(); + if (stringMap.isNotEmpty) { + final Object? data = json.decode(stringMap); + if (data is Map) { + preferences = data.cast(); + } + } + } + return preferences; +} + +/// Writes the cached preferences to disk. Returns [true] if the operation +/// succeeded. +Future _writePreferences( + Map preferences, + String fileName, { + FileSystem fs = const LocalFileSystem(), + PathProviderLinux? pathProvider, +}) async { + try { + final File? localDataFile = await _getLocalDataFile( + fileName, + fs: fs, + pathProvider: pathProvider, + ); + if (localDataFile == null) { + debugPrint('Unable to determine where to write preferences.'); + return false; + } + if (!localDataFile.existsSync()) { + localDataFile.createSync(recursive: true); + } + final String stringMap = json.encode(preferences); + localDataFile.writeAsStringSync(stringMap); + } catch (e) { + debugPrint('Error saving preferences to disk: $e'); + return false; + } + return true; +} + +/// Linux specific SharedPreferences Options. +class SharedPreferencesLinuxOptions extends SharedPreferencesOptions { + /// Constructor for SharedPreferencesLinuxOptions. + const SharedPreferencesLinuxOptions({ + this.fileName = 'shared_preferences', + }); + + /// The name of the file to store preferences in. + final String fileName; + + /// Returns a new instance of [SharedPreferencesLinuxOptions] from an existing + /// [SharedPreferencesOptions]. + static SharedPreferencesLinuxOptions fromSharedPreferencesOptions( + SharedPreferencesOptions options) { + if (options is SharedPreferencesLinuxOptions) { + return options; + } + return const SharedPreferencesLinuxOptions(); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/pubspec.yaml b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/pubspec.yaml new file mode 100644 index 00000000..c43a21bd --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux/pubspec.yaml @@ -0,0 +1,34 @@ +name: shared_preferences_linux +description: Linux implementation of the shared_preferences plugin +repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_linux +issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 +version: 2.4.1 + +environment: + sdk: ^3.3.0 + flutter: ">=3.19.0" + +flutter: + plugin: + implements: shared_preferences + platforms: + linux: + dartPluginClass: SharedPreferencesLinux + +dependencies: + file: ">=6.0.0 <8.0.0" + flutter: + sdk: flutter + path: ^1.8.0 + path_provider_linux: ^2.0.0 + path_provider_platform_interface: ^2.0.0 + shared_preferences_platform_interface: ^2.4.0 + +dev_dependencies: + flutter_test: + sdk: flutter + +topics: + - persistence + - shared-preferences + - storage diff --git a/linux/flutter/ephemeral/.plugin_symlinks/syncfusion_pdfviewer_linux/pubspec.yaml b/linux/flutter/ephemeral/.plugin_symlinks/syncfusion_pdfviewer_linux/pubspec.yaml index 870634f3..ced0bed9 100644 --- a/linux/flutter/ephemeral/.plugin_symlinks/syncfusion_pdfviewer_linux/pubspec.yaml +++ b/linux/flutter/ephemeral/.plugin_symlinks/syncfusion_pdfviewer_linux/pubspec.yaml @@ -1,11 +1,11 @@ name: syncfusion_pdfviewer_linux description: Linux platform implementation of the Flutter PDF Viewer library that lets you view the PDF documents seamlessly and efficiently. -version: 31.1.17 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_pdfviewer_linux environment: sdk: ^3.7.0 - flutter: '>=3.29.0' + flutter: '>=3.35.1' flutter: plugin: diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/AUTHORS b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/AUTHORS new file mode 100644 index 00000000..493a0b4e --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/AUTHORS @@ -0,0 +1,66 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +The Chromium Authors +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/CHANGELOG.md b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/CHANGELOG.md new file mode 100644 index 00000000..f0afca15 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/CHANGELOG.md @@ -0,0 +1,110 @@ +## 3.2.2 + +* Updates to Pigeon 26. +* Updates minimum supported SDK version to Flutter 3.32/Dart 3.8. + +## 3.2.1 + +* Updates Pigeon to resolve a compilation failure with some versions of glib. + +## 3.2.0 + +* Updates platform channels to use Pigeon. +* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. + +## 3.1.1 + +* Implements `launchUrl`. +* Simplifies method channel interface by removing unused elements. +* Updates minimum supported SDK version to Flutter 3.10/Dart 3.0. + +## 3.1.0 + +* Implements `supportsMode` and `supportsCloseForMode`. + +## 3.0.6 + +* Adds pub topics to package metadata. +* Updates minimum supported SDK version to Flutter 3.7/Dart 2.19. + +## 3.0.5 + +* Sets a cmake_policy compatibility version to fix build warnings. + +## 3.0.4 + +* Clarifies explanation of endorsement in README. +* Aligns Dart and Flutter SDK constraints. + +## 3.0.3 + +* Updates links for the merge of flutter/plugins into flutter/packages. +* Updates minimum Flutter version to 3.0. + +## 3.0.2 + +* Updates code for stricter lint checks. +* Updates minimum Flutter version to 2.10. + +## 3.0.1 + +* Fixes library_private_types_in_public_api, sort_child_properties_last and use_key_in_widget_constructors + lint warnings. + +## 3.0.0 + +* Changes the major version since, due to a typo in `default_package` in + existing versions of `url_launcher`, requiring Dart registration in this + package is in practice a breaking change. + * Does not include any API changes; clients can allow both 2.x or 3.x. + +## 2.0.4 + +* **\[Retracted\]** Switches to an in-package method channel implementation. + +## 2.0.3 + +* Updates code for new analysis options. +* Fix minor memory leak in Linux url_launcher tests. +* Fixes canLaunch detection for URIs addressing on local or network file systems + +## 2.0.2 + +* Replaced reference to `shared_preferences` plugin with the `url_launcher` in the README. + +## 2.0.1 + +* Updated installation instructions in README. + +## 2.0.0 + +* Migrate to null safety. +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) +* Set `implementation` in pubspec.yaml + +## 0.0.2+1 + +* Update Flutter SDK constraint. + +## 0.0.2 + +* Update integration test examples to use `testWidgets` instead of `test`. + +## 0.0.1+4 + +* Update Dart SDK constraint in example. + +## 0.0.1+3 + +* Add a missing include. + +## 0.0.1+2 + +* Check in linux/ directory for example/ + +# 0.0.1+1 +* README update for endorsement by url_launcher. + +# 0.0.1 +* The initial implementation of url_launcher for Linux diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/integration_test/url_launcher_test.dart b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/integration_test/url_launcher_test.dart new file mode 100644 index 00000000..d67d61df --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/integration_test/url_launcher_test.dart @@ -0,0 +1,20 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + testWidgets('canLaunch', (WidgetTester _) async { + final UrlLauncherPlatform launcher = UrlLauncherPlatform.instance; + + expect(await launcher.canLaunch('randomstring'), false); + + // Generally all devices should have some default browser. + expect(await launcher.canLaunch('http://flutter.dev'), true); + }); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/lib/main.dart b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/lib/main.dart new file mode 100644 index 00000000..e8d91be1 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/lib/main.dart @@ -0,0 +1,91 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'URL Launcher', + theme: ThemeData(primarySwatch: Colors.blue), + home: const MyHomePage(title: 'URL Launcher'), + ); + } +} + +class MyHomePage extends StatefulWidget { + const MyHomePage({super.key, required this.title}); + final String title; + + @override + State createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + Future? _launched; + + Future _launchInBrowser(String url) async { + if (await UrlLauncherPlatform.instance.canLaunch(url)) { + await UrlLauncherPlatform.instance.launch( + url, + useSafariVC: false, + useWebView: false, + enableJavaScript: false, + enableDomStorage: false, + universalLinksOnly: false, + headers: {}, + ); + } else { + throw Exception('Could not launch $url'); + } + } + + Widget _launchStatus(BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + return const Text(''); + } + } + + @override + Widget build(BuildContext context) { + const String toLaunch = 'https://www.cylog.org/headers/'; + return Scaffold( + appBar: AppBar(title: Text(widget.title)), + body: ListView( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Padding( + padding: EdgeInsets.all(16.0), + child: Text(toLaunch), + ), + ElevatedButton( + onPressed: () => setState(() { + _launched = _launchInBrowser(toLaunch); + }), + child: const Text('Launch in browser'), + ), + const Padding(padding: EdgeInsets.all(16.0)), + FutureBuilder(future: _launched, builder: _launchStatus), + ], + ), + ], + ), + ); + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/CMakeLists.txt new file mode 100644 index 00000000..11219aa5 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/CMakeLists.txt @@ -0,0 +1,100 @@ +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +set(BINARY_NAME "example") + +cmake_policy(SET CMP0063 NEW) + +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) +apply_standard_settings(${BINARY_NAME}) +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Enable the test target. +set(include_url_launcher_linux_tests TRUE) +# Provide an alias for the test target using the name expected by repo tooling. +add_custom_target(unit_tests DEPENDS url_launcher_linux_test) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/flutter/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..33fd5801 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/flutter/CMakeLists.txt @@ -0,0 +1,87 @@ +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/flutter/generated_plugins.cmake b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..f16b4c34 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/flutter/generated_plugins.cmake @@ -0,0 +1,24 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + url_launcher_linux +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/main.cc b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/main.cc new file mode 100644 index 00000000..3b03bbf6 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/main.cc @@ -0,0 +1,10 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/my_application.cc b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/my_application.cc new file mode 100644 index 00000000..bb60dbd6 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/my_application.cc @@ -0,0 +1,48 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "my_application.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), nullptr)); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/my_application.h b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/my_application.h new file mode 100644 index 00000000..9ae704a9 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/linux/my_application.h @@ -0,0 +1,22 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/pubspec.yaml b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/pubspec.yaml new file mode 100644 index 00000000..bba98221 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/pubspec.yaml @@ -0,0 +1,28 @@ +name: url_launcher_example +description: Demonstrates how to use the url_launcher plugin. +publish_to: none + +environment: + sdk: ^3.8.0 + flutter: ">=3.32.0" + +dependencies: + flutter: + sdk: flutter + url_launcher_linux: + # When depending on this package from a real application you should use: + # url_launcher_linux: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. + path: ../ + url_launcher_platform_interface: ^2.2.0 + +dev_dependencies: + flutter_test: + sdk: flutter + integration_test: + sdk: flutter + +flutter: + uses-material-design: true diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/test_driver/integration_test.dart b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/test_driver/integration_test.dart new file mode 100644 index 00000000..fb3dec00 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/test_driver/integration_test.dart @@ -0,0 +1,7 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/lib/src/messages.g.dart b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/lib/src/messages.g.dart new file mode 100644 index 00000000..6187ef54 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/lib/src/messages.g.dart @@ -0,0 +1,119 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.1.0), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; + +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; + +PlatformException _createConnectionError(String channelName) { + return PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); +} + +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + default: + return super.readValueOfType(type, buffer); + } + } +} + +class UrlLauncherApi { + /// Constructor for [UrlLauncherApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + UrlLauncherApi({ + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + /// Returns true if the URL can definitely be launched. + Future canLaunchUrl(String url) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.url_launcher_linux.UrlLauncherApi.canLaunchUrl$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [url], + ); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + /// Opens the URL externally, returning an error string on failure. + Future launchUrl(String url) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.url_launcher_linux.UrlLauncherApi.launchUrl$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [url], + ); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/lib/url_launcher_linux.dart b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/lib/url_launcher_linux.dart new file mode 100644 index 00000000..6e7acfa0 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/lib/url_launcher_linux.dart @@ -0,0 +1,77 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:url_launcher_platform_interface/link.dart'; +import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; + +import 'src/messages.g.dart'; + +/// An implementation of [UrlLauncherPlatform] for Linux. +class UrlLauncherLinux extends UrlLauncherPlatform { + /// Creates a new URL launcher instance. + UrlLauncherLinux({@visibleForTesting UrlLauncherApi? api}) + : _hostApi = api ?? UrlLauncherApi(); + + /// Registers this class as the default instance of [UrlLauncherPlatform]. + static void registerWith() { + UrlLauncherPlatform.instance = UrlLauncherLinux(); + } + + final UrlLauncherApi _hostApi; + + @override + final LinkDelegate? linkDelegate = null; + + @override + Future canLaunch(String url) async { + return _hostApi.canLaunchUrl(url); + } + + @override + Future launch( + String url, { + required bool useSafariVC, + required bool useWebView, + required bool enableJavaScript, + required bool enableDomStorage, + required bool universalLinksOnly, + required Map headers, + String? webOnlyWindowName, + }) { + // None of the options are supported, so they don't need to be converted to + // LaunchOptions. + return launchUrl(url, const LaunchOptions()); + } + + @override + Future launchUrl(String url, LaunchOptions options) async { + final String? error = await _hostApi.launchUrl(url); + if (error != null) { + // TODO(stuartmorgan): Standardize errors across the entire plugin, + // instead of using PlatformException. This preserves the pre-Pigeon + // behavior of the C code returning this error response. + throw PlatformException( + code: 'Launch Error', + message: 'Failed to launch URL: $error', + ); + } + return true; + } + + @override + Future supportsMode(PreferredLaunchMode mode) async { + return mode == PreferredLaunchMode.platformDefault || + mode == PreferredLaunchMode.externalApplication; + } + + @override + Future supportsCloseForMode(PreferredLaunchMode mode) async { + // No supported mode is closeable. + return false; + } +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/CMakeLists.txt b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/CMakeLists.txt new file mode 100644 index 00000000..a52bd5ad --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/CMakeLists.txt @@ -0,0 +1,65 @@ +cmake_minimum_required(VERSION 3.10) +set(PROJECT_NAME "url_launcher_linux") +project(${PROJECT_NAME} LANGUAGES CXX) + +cmake_policy(VERSION 3.10...3.24) + +set(PLUGIN_NAME "${PROJECT_NAME}_plugin") + +list(APPEND PLUGIN_SOURCES + "messages.g.cc" + "url_launcher_plugin.cc" +) + +add_library(${PLUGIN_NAME} SHARED + ${PLUGIN_SOURCES} +) +apply_standard_settings(${PLUGIN_NAME}) +set_target_properties(${PLUGIN_NAME} PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) +target_include_directories(${PLUGIN_NAME} INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/include") +target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) +target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) + + +# === Tests === + +if (${include_${PROJECT_NAME}_tests}) +if(${CMAKE_VERSION} VERSION_LESS "3.11.0") +message("Unit tests require CMake 3.11.0 or later") +else() +set(TEST_RUNNER "${PROJECT_NAME}_test") +enable_testing() +# TODO(stuartmorgan): Consider using a single shared, pre-checked-in googletest +# instance rather than downloading for each plugin. This approach makes sense +# for a template, but not for a monorepo with many plugins. +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/release-1.11.0.zip +) +# Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +# Disable install commands for gtest so it doesn't end up in the bundle. +set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE) + +FetchContent_MakeAvailable(googletest) + +# The plugin's exported API is not very useful for unit testing, so build the +# sources directly into the test binary rather than using the shared library. +add_executable(${TEST_RUNNER} + test/url_launcher_linux_test.cc + ${PLUGIN_SOURCES} +) +apply_standard_settings(${TEST_RUNNER}) +target_include_directories(${TEST_RUNNER} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") +target_link_libraries(${TEST_RUNNER} PRIVATE flutter) +target_link_libraries(${TEST_RUNNER} PRIVATE PkgConfig::GTK) +target_link_libraries(${TEST_RUNNER} PRIVATE gtest_main gmock) + +include(GoogleTest) +gtest_discover_tests(${TEST_RUNNER}) +endif() # CMake version check +endif() # include_${PROJECT_NAME}_tests diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/include/url_launcher_linux/url_launcher_plugin.h b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/include/url_launcher_linux/url_launcher_plugin.h new file mode 100644 index 00000000..09572ca9 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/include/url_launcher_linux/url_launcher_plugin.h @@ -0,0 +1,31 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PACKAGES_URL_LAUNCHER_URL_LAUNCHER_LINUX_LINUX_INCLUDE_URL_LAUNCHER_URL_LAUNCHER_PLUGIN_H_ +#define PACKAGES_URL_LAUNCHER_URL_LAUNCHER_LINUX_LINUX_INCLUDE_URL_LAUNCHER_URL_LAUNCHER_PLUGIN_H_ + +// A plugin to launch URLs. + +#include + +G_BEGIN_DECLS + +#ifdef FLUTTER_PLUGIN_IMPL +#define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) +#else +#define FLUTTER_PLUGIN_EXPORT +#endif + +G_DECLARE_FINAL_TYPE(FlUrlLauncherPlugin, fl_url_launcher_plugin, FL, + URL_LAUNCHER_PLUGIN, GObject) + +FLUTTER_PLUGIN_EXPORT FlUrlLauncherPlugin* fl_url_launcher_plugin_new( + FlPluginRegistrar* registrar); + +FLUTTER_PLUGIN_EXPORT void url_launcher_plugin_register_with_registrar( + FlPluginRegistrar* registrar); + +G_END_DECLS + +#endif // PACKAGES_URL_LAUNCHER_URL_LAUNCHER_LINUX_LINUX_INCLUDE_URL_LAUNCHER_URL_LAUNCHER_PLUGIN_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/messages.g.cc b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/messages.g.cc new file mode 100644 index 00000000..f91c6cf9 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/messages.g.cc @@ -0,0 +1,300 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.1.0), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +#include "messages.g.h" + +struct _FulMessageCodec { + FlStandardMessageCodec parent_instance; +}; + +G_DEFINE_TYPE(FulMessageCodec, ful_message_codec, + fl_standard_message_codec_get_type()) + +static gboolean ful_message_codec_write_value(FlStandardMessageCodec* codec, + GByteArray* buffer, + FlValue* value, GError** error) { + if (fl_value_get_type(value) == FL_VALUE_TYPE_CUSTOM) { + switch (fl_value_get_custom_type(value)) {} + } + + return FL_STANDARD_MESSAGE_CODEC_CLASS(ful_message_codec_parent_class) + ->write_value(codec, buffer, value, error); +} + +static FlValue* ful_message_codec_read_value_of_type( + FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, int type, + GError** error) { + switch (type) { + default: + return FL_STANDARD_MESSAGE_CODEC_CLASS(ful_message_codec_parent_class) + ->read_value_of_type(codec, buffer, offset, type, error); + } +} + +static void ful_message_codec_init(FulMessageCodec* self) {} + +static void ful_message_codec_class_init(FulMessageCodecClass* klass) { + FL_STANDARD_MESSAGE_CODEC_CLASS(klass)->write_value = + ful_message_codec_write_value; + FL_STANDARD_MESSAGE_CODEC_CLASS(klass)->read_value_of_type = + ful_message_codec_read_value_of_type; +} + +static FulMessageCodec* ful_message_codec_new() { + FulMessageCodec* self = + FUL_MESSAGE_CODEC(g_object_new(ful_message_codec_get_type(), nullptr)); + return self; +} + +struct _FulUrlLauncherApiCanLaunchUrlResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE(FulUrlLauncherApiCanLaunchUrlResponse, + ful_url_launcher_api_can_launch_url_response, G_TYPE_OBJECT) + +static void ful_url_launcher_api_can_launch_url_response_dispose( + GObject* object) { + FulUrlLauncherApiCanLaunchUrlResponse* self = + FUL_URL_LAUNCHER_API_CAN_LAUNCH_URL_RESPONSE(object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS(ful_url_launcher_api_can_launch_url_response_parent_class) + ->dispose(object); +} + +static void ful_url_launcher_api_can_launch_url_response_init( + FulUrlLauncherApiCanLaunchUrlResponse* self) {} + +static void ful_url_launcher_api_can_launch_url_response_class_init( + FulUrlLauncherApiCanLaunchUrlResponseClass* klass) { + G_OBJECT_CLASS(klass)->dispose = + ful_url_launcher_api_can_launch_url_response_dispose; +} + +FulUrlLauncherApiCanLaunchUrlResponse* +ful_url_launcher_api_can_launch_url_response_new(gboolean return_value) { + FulUrlLauncherApiCanLaunchUrlResponse* self = + FUL_URL_LAUNCHER_API_CAN_LAUNCH_URL_RESPONSE(g_object_new( + ful_url_launcher_api_can_launch_url_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_bool(return_value)); + return self; +} + +FulUrlLauncherApiCanLaunchUrlResponse* +ful_url_launcher_api_can_launch_url_response_new_error(const gchar* code, + const gchar* message, + FlValue* details) { + FulUrlLauncherApiCanLaunchUrlResponse* self = + FUL_URL_LAUNCHER_API_CAN_LAUNCH_URL_RESPONSE(g_object_new( + ful_url_launcher_api_can_launch_url_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, + fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) + : fl_value_new_null()); + return self; +} + +struct _FulUrlLauncherApiLaunchUrlResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE(FulUrlLauncherApiLaunchUrlResponse, + ful_url_launcher_api_launch_url_response, G_TYPE_OBJECT) + +static void ful_url_launcher_api_launch_url_response_dispose(GObject* object) { + FulUrlLauncherApiLaunchUrlResponse* self = + FUL_URL_LAUNCHER_API_LAUNCH_URL_RESPONSE(object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS(ful_url_launcher_api_launch_url_response_parent_class) + ->dispose(object); +} + +static void ful_url_launcher_api_launch_url_response_init( + FulUrlLauncherApiLaunchUrlResponse* self) {} + +static void ful_url_launcher_api_launch_url_response_class_init( + FulUrlLauncherApiLaunchUrlResponseClass* klass) { + G_OBJECT_CLASS(klass)->dispose = + ful_url_launcher_api_launch_url_response_dispose; +} + +FulUrlLauncherApiLaunchUrlResponse* +ful_url_launcher_api_launch_url_response_new(const gchar* return_value) { + FulUrlLauncherApiLaunchUrlResponse* self = + FUL_URL_LAUNCHER_API_LAUNCH_URL_RESPONSE(g_object_new( + ful_url_launcher_api_launch_url_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, return_value != nullptr + ? fl_value_new_string(return_value) + : fl_value_new_null()); + return self; +} + +FulUrlLauncherApiLaunchUrlResponse* +ful_url_launcher_api_launch_url_response_new_error(const gchar* code, + const gchar* message, + FlValue* details) { + FulUrlLauncherApiLaunchUrlResponse* self = + FUL_URL_LAUNCHER_API_LAUNCH_URL_RESPONSE(g_object_new( + ful_url_launcher_api_launch_url_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, + fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) + : fl_value_new_null()); + return self; +} + +struct _FulUrlLauncherApi { + GObject parent_instance; + + const FulUrlLauncherApiVTable* vtable; + gpointer user_data; + GDestroyNotify user_data_free_func; +}; + +G_DEFINE_TYPE(FulUrlLauncherApi, ful_url_launcher_api, G_TYPE_OBJECT) + +static void ful_url_launcher_api_dispose(GObject* object) { + FulUrlLauncherApi* self = FUL_URL_LAUNCHER_API(object); + if (self->user_data != nullptr) { + self->user_data_free_func(self->user_data); + } + self->user_data = nullptr; + G_OBJECT_CLASS(ful_url_launcher_api_parent_class)->dispose(object); +} + +static void ful_url_launcher_api_init(FulUrlLauncherApi* self) {} + +static void ful_url_launcher_api_class_init(FulUrlLauncherApiClass* klass) { + G_OBJECT_CLASS(klass)->dispose = ful_url_launcher_api_dispose; +} + +static FulUrlLauncherApi* ful_url_launcher_api_new( + const FulUrlLauncherApiVTable* vtable, gpointer user_data, + GDestroyNotify user_data_free_func) { + FulUrlLauncherApi* self = FUL_URL_LAUNCHER_API( + g_object_new(ful_url_launcher_api_get_type(), nullptr)); + self->vtable = vtable; + self->user_data = user_data; + self->user_data_free_func = user_data_free_func; + return self; +} + +static void ful_url_launcher_api_can_launch_url_cb( + FlBasicMessageChannel* channel, FlValue* message_, + FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + FulUrlLauncherApi* self = FUL_URL_LAUNCHER_API(user_data); + + if (self->vtable == nullptr || self->vtable->can_launch_url == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + const gchar* url = fl_value_get_string(value0); + g_autoptr(FulUrlLauncherApiCanLaunchUrlResponse) response = + self->vtable->can_launch_url(url, self->user_data); + if (response == nullptr) { + g_warning("No response returned to %s.%s", "UrlLauncherApi", + "canLaunchUrl"); + return; + } + + g_autoptr(GError) error = NULL; + if (!fl_basic_message_channel_respond(channel, response_handle, + response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "UrlLauncherApi", + "canLaunchUrl", error->message); + } +} + +static void ful_url_launcher_api_launch_url_cb( + FlBasicMessageChannel* channel, FlValue* message_, + FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + FulUrlLauncherApi* self = FUL_URL_LAUNCHER_API(user_data); + + if (self->vtable == nullptr || self->vtable->launch_url == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + const gchar* url = fl_value_get_string(value0); + g_autoptr(FulUrlLauncherApiLaunchUrlResponse) response = + self->vtable->launch_url(url, self->user_data); + if (response == nullptr) { + g_warning("No response returned to %s.%s", "UrlLauncherApi", "launchUrl"); + return; + } + + g_autoptr(GError) error = NULL; + if (!fl_basic_message_channel_respond(channel, response_handle, + response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "UrlLauncherApi", + "launchUrl", error->message); + } +} + +void ful_url_launcher_api_set_method_handlers( + FlBinaryMessenger* messenger, const gchar* suffix, + const FulUrlLauncherApiVTable* vtable, gpointer user_data, + GDestroyNotify user_data_free_func) { + g_autofree gchar* dot_suffix = + suffix != nullptr ? g_strdup_printf(".%s", suffix) : g_strdup(""); + g_autoptr(FulUrlLauncherApi) api_data = + ful_url_launcher_api_new(vtable, user_data, user_data_free_func); + + g_autoptr(FulMessageCodec) codec = ful_message_codec_new(); + g_autofree gchar* can_launch_url_channel_name = g_strdup_printf( + "dev.flutter.pigeon.url_launcher_linux.UrlLauncherApi.canLaunchUrl%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) can_launch_url_channel = + fl_basic_message_channel_new(messenger, can_launch_url_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + can_launch_url_channel, ful_url_launcher_api_can_launch_url_cb, + g_object_ref(api_data), g_object_unref); + g_autofree gchar* launch_url_channel_name = g_strdup_printf( + "dev.flutter.pigeon.url_launcher_linux.UrlLauncherApi.launchUrl%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) launch_url_channel = + fl_basic_message_channel_new(messenger, launch_url_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + launch_url_channel, ful_url_launcher_api_launch_url_cb, + g_object_ref(api_data), g_object_unref); +} + +void ful_url_launcher_api_clear_method_handlers(FlBinaryMessenger* messenger, + const gchar* suffix) { + g_autofree gchar* dot_suffix = + suffix != nullptr ? g_strdup_printf(".%s", suffix) : g_strdup(""); + + g_autoptr(FulMessageCodec) codec = ful_message_codec_new(); + g_autofree gchar* can_launch_url_channel_name = g_strdup_printf( + "dev.flutter.pigeon.url_launcher_linux.UrlLauncherApi.canLaunchUrl%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) can_launch_url_channel = + fl_basic_message_channel_new(messenger, can_launch_url_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(can_launch_url_channel, nullptr, + nullptr, nullptr); + g_autofree gchar* launch_url_channel_name = g_strdup_printf( + "dev.flutter.pigeon.url_launcher_linux.UrlLauncherApi.launchUrl%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) launch_url_channel = + fl_basic_message_channel_new(messenger, launch_url_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(launch_url_channel, nullptr, + nullptr, nullptr); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/messages.g.h b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/messages.g.h new file mode 100644 index 00000000..52a981c7 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/messages.g.h @@ -0,0 +1,121 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.1.0), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +#ifndef PIGEON_MESSAGES_G_H_ +#define PIGEON_MESSAGES_G_H_ + +#include + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE(FulMessageCodec, ful_message_codec, FUL, MESSAGE_CODEC, + FlStandardMessageCodec) + +G_DECLARE_FINAL_TYPE(FulUrlLauncherApi, ful_url_launcher_api, FUL, + URL_LAUNCHER_API, GObject) + +G_DECLARE_FINAL_TYPE(FulUrlLauncherApiCanLaunchUrlResponse, + ful_url_launcher_api_can_launch_url_response, FUL, + URL_LAUNCHER_API_CAN_LAUNCH_URL_RESPONSE, GObject) + +/** + * ful_url_launcher_api_can_launch_url_response_new: + * + * Creates a new response to UrlLauncherApi.canLaunchUrl. + * + * Returns: a new #FulUrlLauncherApiCanLaunchUrlResponse + */ +FulUrlLauncherApiCanLaunchUrlResponse* +ful_url_launcher_api_can_launch_url_response_new(gboolean return_value); + +/** + * ful_url_launcher_api_can_launch_url_response_new_error: + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Creates a new error response to UrlLauncherApi.canLaunchUrl. + * + * Returns: a new #FulUrlLauncherApiCanLaunchUrlResponse + */ +FulUrlLauncherApiCanLaunchUrlResponse* +ful_url_launcher_api_can_launch_url_response_new_error(const gchar* code, + const gchar* message, + FlValue* details); + +G_DECLARE_FINAL_TYPE(FulUrlLauncherApiLaunchUrlResponse, + ful_url_launcher_api_launch_url_response, FUL, + URL_LAUNCHER_API_LAUNCH_URL_RESPONSE, GObject) + +/** + * ful_url_launcher_api_launch_url_response_new: + * + * Creates a new response to UrlLauncherApi.launchUrl. + * + * Returns: a new #FulUrlLauncherApiLaunchUrlResponse + */ +FulUrlLauncherApiLaunchUrlResponse* +ful_url_launcher_api_launch_url_response_new(const gchar* return_value); + +/** + * ful_url_launcher_api_launch_url_response_new_error: + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Creates a new error response to UrlLauncherApi.launchUrl. + * + * Returns: a new #FulUrlLauncherApiLaunchUrlResponse + */ +FulUrlLauncherApiLaunchUrlResponse* +ful_url_launcher_api_launch_url_response_new_error(const gchar* code, + const gchar* message, + FlValue* details); + +/** + * FulUrlLauncherApiVTable: + * + * Table of functions exposed by UrlLauncherApi to be implemented by the API + * provider. + */ +typedef struct { + FulUrlLauncherApiCanLaunchUrlResponse* (*can_launch_url)(const gchar* url, + gpointer user_data); + FulUrlLauncherApiLaunchUrlResponse* (*launch_url)(const gchar* url, + gpointer user_data); +} FulUrlLauncherApiVTable; + +/** + * ful_url_launcher_api_set_method_handlers: + * + * @messenger: an #FlBinaryMessenger. + * @suffix: (allow-none): a suffix to add to the API or %NULL for none. + * @vtable: implementations of the methods in this API. + * @user_data: (closure): user data to pass to the functions in @vtable. + * @user_data_free_func: (allow-none): a function which gets called to free + * @user_data, or %NULL. + * + * Connects the method handlers in the UrlLauncherApi API. + */ +void ful_url_launcher_api_set_method_handlers( + FlBinaryMessenger* messenger, const gchar* suffix, + const FulUrlLauncherApiVTable* vtable, gpointer user_data, + GDestroyNotify user_data_free_func); + +/** + * ful_url_launcher_api_clear_method_handlers: + * + * @messenger: an #FlBinaryMessenger. + * @suffix: (allow-none): a suffix to add to the API or %NULL for none. + * + * Clears the method handlers in the UrlLauncherApi API. + */ +void ful_url_launcher_api_clear_method_handlers(FlBinaryMessenger* messenger, + const gchar* suffix); + +G_END_DECLS + +#endif // PIGEON_MESSAGES_G_H_ diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/url_launcher_plugin.cc b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/url_launcher_plugin.cc new file mode 100644 index 00000000..c55fb70d --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/url_launcher_plugin.cc @@ -0,0 +1,109 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "include/url_launcher_linux/url_launcher_plugin.h" + +#include +#include + +#include + +#include "messages.g.h" +#include "url_launcher_plugin_private.h" + +struct _FlUrlLauncherPlugin { + GObject parent_instance; + + FlPluginRegistrar* registrar; +}; + +G_DEFINE_TYPE(FlUrlLauncherPlugin, fl_url_launcher_plugin, g_object_get_type()) + +// Checks if URI has launchable file resource. +static gboolean can_launch_uri_with_file_resource(FlUrlLauncherPlugin* self, + const gchar* url) { + g_autoptr(GError) error = nullptr; + g_autoptr(GFile) file = g_file_new_for_uri(url); + g_autoptr(GAppInfo) app_info = + g_file_query_default_handler(file, NULL, &error); + return app_info != nullptr; +} + +FulUrlLauncherApiCanLaunchUrlResponse* handle_can_launch_url( + const gchar* url, gpointer user_data) { + FlUrlLauncherPlugin* self = FL_URL_LAUNCHER_PLUGIN(user_data); + + gboolean is_launchable = FALSE; + g_autofree gchar* scheme = g_uri_parse_scheme(url); + if (scheme != nullptr) { + g_autoptr(GAppInfo) app_info = + g_app_info_get_default_for_uri_scheme(scheme); + is_launchable = app_info != nullptr; + + if (!is_launchable) { + is_launchable = can_launch_uri_with_file_resource(self, url); + } + } + + return ful_url_launcher_api_can_launch_url_response_new(is_launchable); +} + +// Called when a URL should launch. +static FulUrlLauncherApiLaunchUrlResponse* handle_launch_url( + const gchar* url, gpointer user_data) { + FlUrlLauncherPlugin* self = FL_URL_LAUNCHER_PLUGIN(user_data); + + FlView* view = fl_plugin_registrar_get_view(self->registrar); + g_autoptr(GError) error = nullptr; + gboolean launched; + if (view != nullptr) { + GtkWindow* window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))); + launched = gtk_show_uri_on_window(window, url, GDK_CURRENT_TIME, &error); + } else { + launched = g_app_info_launch_default_for_uri(url, nullptr, &error); + } + if (!launched) { + return ful_url_launcher_api_launch_url_response_new(error->message); + } + + return ful_url_launcher_api_launch_url_response_new(nullptr); +} + +static void fl_url_launcher_plugin_dispose(GObject* object) { + FlUrlLauncherPlugin* self = FL_URL_LAUNCHER_PLUGIN(object); + + ful_url_launcher_api_clear_method_handlers( + fl_plugin_registrar_get_messenger(self->registrar), nullptr); + g_clear_object(&self->registrar); + + G_OBJECT_CLASS(fl_url_launcher_plugin_parent_class)->dispose(object); +} + +static void fl_url_launcher_plugin_class_init(FlUrlLauncherPluginClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_url_launcher_plugin_dispose; +} + +FlUrlLauncherPlugin* fl_url_launcher_plugin_new(FlPluginRegistrar* registrar) { + FlUrlLauncherPlugin* self = FL_URL_LAUNCHER_PLUGIN( + g_object_new(fl_url_launcher_plugin_get_type(), nullptr)); + + self->registrar = FL_PLUGIN_REGISTRAR(g_object_ref(registrar)); + + static FulUrlLauncherApiVTable api_vtable = { + .can_launch_url = handle_can_launch_url, + .launch_url = handle_launch_url, + }; + ful_url_launcher_api_set_method_handlers( + fl_plugin_registrar_get_messenger(registrar), nullptr, &api_vtable, + g_object_ref(self), g_object_unref); + + return self; +} + +static void fl_url_launcher_plugin_init(FlUrlLauncherPlugin* self) {} + +void url_launcher_plugin_register_with_registrar(FlPluginRegistrar* registrar) { + FlUrlLauncherPlugin* plugin = fl_url_launcher_plugin_new(registrar); + g_object_unref(plugin); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/url_launcher_plugin_private.h b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/url_launcher_plugin_private.h new file mode 100644 index 00000000..6e34a52f --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/linux/url_launcher_plugin_private.h @@ -0,0 +1,12 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include "include/url_launcher_linux/url_launcher_plugin.h" +#include "messages.g.h" + +// Called to check if a URL can be launched. +FulUrlLauncherApiCanLaunchUrlResponse* handle_can_launch_url( + const gchar* url, gpointer user_data); diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/pigeons/copyright.txt b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/pigeons/copyright.txt new file mode 100644 index 00000000..07e5f859 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/pigeons/copyright.txt @@ -0,0 +1,3 @@ +Copyright 2013 The Flutter Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/pigeons/messages.dart b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/pigeons/messages.dart new file mode 100644 index 00000000..4f77d8f2 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/pigeons/messages.dart @@ -0,0 +1,23 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:pigeon/pigeon.dart'; + +@ConfigurePigeon( + PigeonOptions( + dartOut: 'lib/src/messages.g.dart', + gobjectHeaderOut: 'linux/messages.g.h', + gobjectSourceOut: 'linux/messages.g.cc', + gobjectOptions: GObjectOptions(module: 'Ful'), + copyrightHeader: 'pigeons/copyright.txt', + ), +) +@HostApi() +abstract class UrlLauncherApi { + /// Returns true if the URL can definitely be launched. + bool canLaunchUrl(String url); + + /// Opens the URL externally, returning an error string on failure. + String? launchUrl(String url); +} diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/pubspec.yaml b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/pubspec.yaml new file mode 100644 index 00000000..5f17be53 --- /dev/null +++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/pubspec.yaml @@ -0,0 +1,34 @@ +name: url_launcher_linux +description: Linux implementation of the url_launcher plugin. +repository: https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_linux +issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+url_launcher%22 +version: 3.2.2 + +environment: + sdk: ^3.8.0 + flutter: ">=3.32.0" + +flutter: + plugin: + implements: url_launcher + platforms: + linux: + pluginClass: UrlLauncherPlugin + dartPluginClass: UrlLauncherLinux + +dependencies: + flutter: + sdk: flutter + url_launcher_platform_interface: ^2.2.0 + +dev_dependencies: + flutter_test: + sdk: flutter + pigeon: ^26.1.0 + test: ^1.16.3 + +topics: + - links + - os-integration + - url-launcher + - urls diff --git a/macos/Runner/DebugProfile.entitlements b/macos/Runner/DebugProfile.entitlements index dc6980c9..1f6a38b1 100644 --- a/macos/Runner/DebugProfile.entitlements +++ b/macos/Runner/DebugProfile.entitlements @@ -10,7 +10,7 @@ com.apple.security.network.client - com.apple.security.network.server + com.apple.security.network.client diff --git a/pubspec.yaml b/pubspec.yaml index 4c1ab30a..1f37a58a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,11 +1,12 @@ + name: flutter_examples description: This project contains the Syncfusion Flutter UI widgets examples. -version: 31.1.17 +version: 32.1.19 homepage: https://github.com/syncfusion/flutter-examples environment: sdk: ^3.7.0 - flutter: '>=3.29.0' + flutter: '>=3.35.1' flutter: uses-material-design: true @@ -98,18 +99,18 @@ dependencies: flutter_markdown: ^0.7.4+1 google_generative_ai: ^0.4.6 path_provider_foundation: ^2.1.0 - syncfusion_localizations: ^31.1.17 - syncfusion_flutter_datagrid_export: ^31.1.17 - syncfusion_flutter_calendar: ^31.1.17 - syncfusion_flutter_datepicker: ^31.1.17 - syncfusion_flutter_charts: ^31.1.17 - syncfusion_flutter_gauges: ^31.1.17 - syncfusion_flutter_sliders: ^31.1.17 - syncfusion_flutter_pdf: ^31.1.17 - syncfusion_flutter_barcodes: ^31.1.17 - syncfusion_officechart: ^31.1.17 - syncfusion_flutter_maps: ^31.1.17 - syncfusion_flutter_signaturepad: ^31.1.17 - syncfusion_flutter_pdfviewer: ^31.1.17 - syncfusion_flutter_treemap: ^31.1.17 - syncfusion_flutter_chat: ^31.1.17 + syncfusion_localizations: ^32.1.19 + syncfusion_flutter_datagrid_export: ^32.1.19 + syncfusion_flutter_calendar: ^32.1.19 + syncfusion_flutter_datepicker: ^32.1.19 + syncfusion_flutter_charts: ^32.1.19 + syncfusion_flutter_gauges: ^32.1.19 + syncfusion_flutter_sliders: ^32.1.19 + syncfusion_flutter_pdf: ^32.1.19 + syncfusion_flutter_barcodes: ^32.1.19 + syncfusion_officechart: ^32.1.19 + syncfusion_flutter_maps: ^32.1.19 + syncfusion_flutter_signaturepad: ^32.1.19 + syncfusion_flutter_pdfviewer: ^32.1.19 + syncfusion_flutter_treemap: ^32.1.19 + syncfusion_flutter_chat: ^32.1.19