diff --git a/.metadata b/.metadata index d1f7051..6884bd8 100644 --- a/.metadata +++ b/.metadata @@ -4,8 +4,8 @@ # This file should be version controlled. version: - revision: 5293f3cd4427b4b48ed155e7a3852c6b3c53d94a - channel: beta + revision: f72efea43c3013323d1b95cff571f3c1caa37583 + channel: stable project_type: app @@ -13,11 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: 5293f3cd4427b4b48ed155e7a3852c6b3c53d94a - base_revision: 5293f3cd4427b4b48ed155e7a3852c6b3c53d94a + create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 + base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 - platform: windows - create_revision: 5293f3cd4427b4b48ed155e7a3852c6b3c53d94a - base_revision: 5293f3cd4427b4b48ed155e7a3852c6b3c53d94a + create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 + base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 # User provided section diff --git a/lib/globals.dart b/lib/globals.dart index c6e003e..e1a6476 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -1,7 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -late String token; TextStyle globalTextStyle = TextStyle(color: Colors.grey[350]); const proxyHeader = kDebugMode || !kIsWeb ? 'https://' : 'http://127.0.0.1:8080/'; diff --git a/lib/main.dart b/lib/main.dart index 4476653..b00d73b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,13 +3,9 @@ import 'package:fipy/providers/player.dart'; import 'package:fipy/screens/home.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:kplayer/kplayer.dart'; -import 'package:kplayer_with_audioplayers/kplayer_with_audioplayers.dart' as kp; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - Player.boot(); - kp.Player.boot(); runApp(const FipyApp()); } @@ -27,7 +23,7 @@ class FipyApp extends StatelessWidget { child: MaterialApp( title: 'Fipy', theme: ThemeData( - primarySwatch: Colors.blue, backgroundColor: Colors.grey[900]), + colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.blue).copyWith(background: Colors.grey[900])), home: const HomeScreen(title: 'Fipy'), ), ); diff --git a/lib/models/track.dart b/lib/models/track.dart index 0229954..47c1ada 100644 --- a/lib/models/track.dart +++ b/lib/models/track.dart @@ -8,6 +8,7 @@ class Track { String? image; String? imageUrl; String? id; + Duration? position; Duration? duration; File? file; @@ -18,6 +19,7 @@ class Track { this.album, this.id, this.duration, + this.position, this.file, this.image, this.imageUrl}); diff --git a/lib/providers/home.dart b/lib/providers/home.dart index 1e38b78..5fabdc6 100644 --- a/lib/providers/home.dart +++ b/lib/providers/home.dart @@ -6,23 +6,21 @@ import 'package:flutter/foundation.dart'; import 'package:universal_io/io.dart'; import 'package:fipy/models/track.dart'; import 'package:flutter/material.dart'; -import 'package:kplayer/kplayer.dart'; import 'package:path_provider/path_provider.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; import 'package:fipy/providers/player.dart'; import 'package:provider/provider.dart'; import 'package:http/http.dart'; import 'package:audioplayers/audioplayers.dart'; -import 'package:kplayer_with_audioplayers/kplayer_with_audioplayers.dart' as kp; class HomeProvider with ChangeNotifier { Track? currentTrack; - PlayerController? player; - AudioPlayer audioPlayer = AudioPlayer(); + AudioPlayer player = AudioPlayer(playerId: 'fipyPlayerID'); List trackList = []; int trackNbr = 0; int userPageNbr = 3; + double currentVolume = 1; Future> getTracks(String radio, {String cursor = ''}) async { int pageNbr = 0; @@ -82,14 +80,10 @@ class HomeProvider with ChangeNotifier { // track = trackList[track.number - 1]; currentTrack = track; - final currentVolume = player?.volume ?? 1; - if (player?.playing ?? false) player?.stop(); - Future.delayed(const Duration(milliseconds: 5)); - if (track.id == null) { final secondMatch = track.artiste == '' ? track.album : track.artiste; final resultUrl = await yt.search - .search(track.title + ' ' + secondMatch!, filter: TypeFilters.video); + .search('${track.title} ${secondMatch!}', filter: TypeFilters.video); track.id = resultUrl.first.id.value; } const invidiousUrl = [ @@ -99,45 +93,35 @@ class HomeProvider with ChangeNotifier { 'invidious.fdn.fr', ]; - // audioPlayer.stop(); - // Future.delayed(const Duration(milliseconds: 5)); - // await audioPlayer.play(DeviceFileSource( - // "https://${invidiousUrl[1]}/latest_version?id=${track.id}&itag=140&local=true&listen=1")); - - final media = PlayerMedia( - type: PlayerMediaType.network, - resource: - "https://${invidiousUrl[1]}/latest_version?id=${track.id}&itag=140&local=true&listen=1"); - player = kp.Player(media: media); - // player = Player.network( - // "https://${invidiousUrl[0]}/latest_version?id=${track.id}&itag=140&local=true&listen=1"); // https://${invidiousUrl[0]}/embed/${track.id}?listen=1&raw=1&local=true - player!.init(); - print(player!.media.resource); - - player!.volume = currentVolume; + player.stop(); + Future.delayed(const Duration(milliseconds: 5)); try { - player!.play(); + final source = UrlSource( + "https://${invidiousUrl[1]}/latest_version?id=${track.id}&itag=140&local=true&listen=1"); + print(source.url); + await player.play(source); } catch (e) { - print('Play error: ' + e.toString()); + print('Play error: $e'); } - Future.delayed(const Duration(milliseconds: 500)); - player!.callback = (PlayerEvent event) { - print(event.name); - if (event.name == 'position') { - currentTrack!.duration = player!.duration; - playerProvider.reload(); - } - if (event.name == 'end' && - currentTrack == track && - (currentTrack!.duration!.inSeconds - player!.position.inSeconds <= - 1)) { - var nextTrack = trackList - .firstWhere((element) => element.number == track.number + 1); - currentTrack = nextTrack; - playTrack(context, nextTrack); - } - }; + Future.delayed(const Duration(milliseconds: 50)); + + player.onDurationChanged.listen((event) async { + currentTrack!.duration = await player.getDuration(); + playerProvider.reload(); + }); + + player.onPositionChanged.listen((position) async { + currentTrack!.position = position; + playerProvider.reload(); + }); + + player.onPlayerComplete.listen((event) { + var nextTrack = + trackList.firstWhere((element) => element.number == track.number + 1); + currentTrack = nextTrack; + playTrack(context, nextTrack); + }); playerProvider.reload(); homeProvider.reload(); @@ -184,27 +168,27 @@ class HomeProvider with ChangeNotifier { List> get radioList { List> menuItems = [ - const DropdownMenuItem(child: Text("FIP"), value: "fip"), - const DropdownMenuItem(child: Text("Electro"), value: "fip_electro"), - const DropdownMenuItem(child: Text("Groove"), value: "fip_groove"), - const DropdownMenuItem(child: Text("Rock"), value: "fip_rock"), - const DropdownMenuItem(child: Text("Jazz"), value: "fip_jazz"), - const DropdownMenuItem(child: Text("Pop"), value: "fip_pop"), - const DropdownMenuItem(child: Text("Reggae"), value: "fip_reggae"), - const DropdownMenuItem(child: Text("World"), value: "fip_world"), + const DropdownMenuItem(value: "fip", child: Text("FIP")), + const DropdownMenuItem(value: "fip_electro", child: Text("Electro")), + const DropdownMenuItem(value: "fip_groove", child: Text("Groove")), + const DropdownMenuItem(value: "fip_rock", child: Text("Rock")), + const DropdownMenuItem(value: "fip_jazz", child: Text("Jazz")), + const DropdownMenuItem(value: "fip_pop", child: Text("Pop")), + const DropdownMenuItem(value: "fip_reggae", child: Text("Reggae")), + const DropdownMenuItem(value: "fip_world", child: Text("World")), const DropdownMenuItem( - child: Text("Nouveautés"), value: "fip_nouveautes"), + value: "fip_nouveautes", child: Text("Nouveautés")), ]; return menuItems; } List> get pageList { List> menuItems = [ - const DropdownMenuItem(child: Text("25"), value: "3"), - const DropdownMenuItem(child: Text("50"), value: "6"), - const DropdownMenuItem(child: Text("100"), value: "12"), - const DropdownMenuItem(child: Text("200"), value: "25"), - const DropdownMenuItem(child: Text("500"), value: "62"), + const DropdownMenuItem(value: "3", child: Text("25")), + const DropdownMenuItem(value: "6", child: Text("50")), + const DropdownMenuItem(value: "12", child: Text("100")), + const DropdownMenuItem(value: "25", child: Text("200")), + const DropdownMenuItem(value: "62", child: Text("500")), ]; return menuItems; } diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 078ae40..1fcf3d3 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -34,8 +34,9 @@ class _HomeScreenState extends State { if (event.runtimeType == RawKeyDownEvent && event.data.logicalKey.keyId == 32) //Enter Key ID from keyboard { - print('tata'); - hp.player?.playing ?? false ? hp.player?.pause() : hp.player?.play(); + hp.player.state.name == 'playing' + ? hp.player.pause() + : hp.player.resume(); } }, child: Stack( @@ -126,7 +127,7 @@ class _HomeScreenState extends State { child: Column(children: [ const SizedBox(height: 20), Text( - 'Error: ' + snapshot.error.toString(), + 'Error: ${snapshot.error}', style: TextStyle(color: Colors.grey[500]), ), ]), @@ -256,23 +257,24 @@ class _HomeScreenState extends State { const SizedBox(width: 1), ElevatedButton( onPressed: () { - hp.player?.playing ?? false - ? hp.player?.pause() - : hp.player?.play(); + hp.player.state.name == 'playing' + ? hp.player.pause() + : hp.player.resume(); + // playerProvider.reload(); }, + style: ElevatedButton.styleFrom( + foregroundColor: Colors.grey[900], + backgroundColor: Colors.grey[300], + shape: const CircleBorder(), + padding: const EdgeInsets.all(12), + ), child: Icon( - hp.player?.playing ?? false + hp.player.state.name == 'playing' ? Icons.pause : Icons.play_arrow, color: Colors.grey[900], size: 30), - style: ElevatedButton.styleFrom( - shape: const CircleBorder(), - padding: const EdgeInsets.all(12), - primary: Colors.grey[300], - onPrimary: Colors.grey[900], - ), ), Column(children: [ IconButton( @@ -297,7 +299,7 @@ class _HomeScreenState extends State { Row(children: [ const SizedBox(width: 70), Text( - timeFormat(hp.player?.position ?? + timeFormat(hp.currentTrack?.position ?? const Duration(seconds: 0)), style: TextStyle(color: Colors.grey[500], fontSize: 12), @@ -314,16 +316,19 @@ class _HomeScreenState extends State { child: SizedBox( width: 300, child: Slider( - value: double.parse( - hp.player?.position.inSeconds.toString() ?? - '0'), - max: double.parse( - hp.player?.duration.inSeconds.toString() ?? - '2000'), + value: double.parse(hp + .currentTrack?.position?.inSeconds + .toString() ?? + '0'), + max: double.parse(hp + .currentTrack?.duration?.inSeconds + .toString() ?? + '2000'), onChanged: (double value) { - if (hp.player?.position != null) { - hp.player!.position = - Duration(seconds: value.toInt()); + if (hp.currentTrack?.position != null) { + hp.player.seek( + Duration(seconds: value.toInt()), + ); playerProvider.reload(); } }, @@ -334,7 +339,7 @@ class _HomeScreenState extends State { ), const SizedBox(width: 3), Text( - timeFormat(hp.player?.duration ?? + timeFormat(hp.currentTrack?.duration ?? const Duration(seconds: 0)), style: TextStyle(color: Colors.grey[500], fontSize: 12), @@ -354,13 +359,12 @@ class _HomeScreenState extends State { child: SizedBox( width: 130, child: Slider( - value: hp.player?.volume ?? 1, + value: hp.currentVolume, max: 1, - onChanged: (double value) { - if (hp.player?.volume != null) { - hp.player!.volume = value; - playerProvider.reload(); - } + onChanged: (double value) async { + hp.currentVolume = value; + await hp.player.setVolume(value); + playerProvider.reload(); }, activeColor: Colors.grey[400], inactiveColor: Colors.grey[700], @@ -383,7 +387,7 @@ Widget trackLine(Track track) { return SizedBox( height: 30, child: Row( - children: [Text(track.title + ' - ' + track.artiste)], + children: [Text('${track.title} - ${track.artiste}')], ), ); } @@ -412,6 +416,15 @@ TableRow _buildTableRow(Track track, BuildContext context) { child: InkWell( onTap: () async { if (track.number != -1) { + // FutureBuilder( + // future: hp.playTrack(context, track), + // builder: ( + // BuildContext context, + // AsyncSnapshot snapshot, + // ) { + // return const SizedBox(); + // }, + // ); hp.playTrack(context, track); } }, @@ -466,10 +479,11 @@ TableRow _buildTableRow(Track track, BuildContext context) { final secondMatch = track.artiste == '' ? track.album : track.artiste; final resultUrl = await yt.search - .search(track.title + ' ' + secondMatch!); + .search('${track.title} ${secondMatch!}'); track.id = resultUrl.first.id.value; } if (track.id != null) { + // ignore: use_build_context_synchronously hp.downloadMusic(context, track); } isDownloading = -1; diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 37d935a..1830e5c 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,14 +6,10 @@ #include "generated_plugin_registrant.h" -#include -#include +#include void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) dart_vlc_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "DartVlcPlugin"); - dart_vlc_plugin_register_with_registrar(dart_vlc_registrar); - g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); - url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); + g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin"); + audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 983d025..e9abb91 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,8 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST - dart_vlc - url_launcher_linux + audioplayers_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/pubspec.lock b/pubspec.lock index b5d2371..334661c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,170 +5,170 @@ packages: dependency: transitive description: name: archive - url: "https://pub.dartlang.org" + sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" + url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "3.3.7" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440" + url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.0" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" source: hosted - version: "2.8.2" - audio_session: - dependency: transitive - description: - name: audio_session - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.6+1" - audio_video_progress_bar: - dependency: transitive - description: - name: audio_video_progress_bar - url: "https://pub.dartlang.org" - source: hosted - version: "0.10.0" + version: "2.10.0" audioplayers: - dependency: transitive + dependency: "direct main" description: name: audioplayers - url: "https://pub.dartlang.org" + sha256: "6063c05f987596ba7a3dad9bb9a5d8adfa5e7c07b9bae5301b27c11d0b3a239f" + url: "https://pub.dev" source: hosted - version: "1.0.0-rc.2" + version: "4.0.1" audioplayers_android: dependency: transitive description: name: audioplayers_android - url: "https://pub.dartlang.org" + sha256: fb6bca878ad175d8f6ddc0e0a2d4226d81fa7c10747c12db420e96c7a096b2cc + url: "https://pub.dev" source: hosted - version: "1.0.0-rc.2" + version: "3.0.1" audioplayers_darwin: dependency: transitive description: name: audioplayers_darwin - url: "https://pub.dartlang.org" + sha256: c4a56c49347b2e85ac4e1efea218948ca0fba87f04d2a3d3de07ce2410037038 + url: "https://pub.dev" source: hosted - version: "1.0.0-rc.2" + version: "4.0.1" + audioplayers_linux: + dependency: transitive + description: + name: audioplayers_linux + sha256: "897e24f190232a3fbb88134b062aa83a9240f55789b5e8d17c114283284ef56b" + url: "https://pub.dev" + source: hosted + version: "2.0.1" audioplayers_platform_interface: dependency: transitive description: name: audioplayers_platform_interface - url: "https://pub.dartlang.org" + sha256: "3a90a46198d375fc7d47bc1d3070c8fd8863b6469b7d87ca80f953efb090f976" + url: "https://pub.dev" source: hosted - version: "1.0.0-rc.2" + version: "5.0.0" audioplayers_web: dependency: transitive description: name: audioplayers_web - url: "https://pub.dartlang.org" + sha256: "4f5dcbfec0bf98ea09e243d5f5b64ea43a4e6710a2f292724bed16cdba3c691e" + url: "https://pub.dev" source: hosted - version: "1.0.0-rc.2" + version: "3.0.1" audioplayers_windows: dependency: transitive description: name: audioplayers_windows - url: "https://pub.dartlang.org" + sha256: "010f575653c01ccbe9756050b18df83d89426740e04b684f6438aa26c775a965" + url: "https://pub.dev" source: hosted - version: "1.0.0-rc.2" + version: "2.0.1" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" + version: "1.2.1" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" csslib: dependency: transitive description: name: csslib - url: "https://pub.dartlang.org" + sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745 + url: "https://pub.dev" source: hosted - version: "0.17.1" + version: "0.17.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" source: hosted - version: "1.0.4" - dart_vlc: - dependency: transitive - description: - name: dart_vlc - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.9" - dart_vlc_ffi: - dependency: transitive - description: - name: dart_vlc_ffi - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.5+1" + version: "1.0.5" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.3.1" ffi: dependency: transitive description: name: ffi - url: "https://pub.dartlang.org" + sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "2.0.1" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" source: hosted - version: "6.1.2" + version: "6.1.4" flutter: dependency: "direct main" description: flutter @@ -178,9 +178,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "2.0.1" flutter_test: dependency: "direct dev" description: flutter @@ -195,142 +196,98 @@ packages: dependency: transitive description: name: freezed_annotation - url: "https://pub.dartlang.org" + sha256: aeac15850ef1b38ee368d4c53ba9a847e900bb2c53a4db3f6881cbb3cb684338 + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "2.2.0" html: dependency: transitive description: name: html - url: "https://pub.dartlang.org" + sha256: "79d498e6d6761925a34ee5ea8fa6dfef38607781d2fa91e37523474282af55cb" + url: "https://pub.dev" source: hosted - version: "0.15.0" + version: "0.15.2" http: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + url: "https://pub.dev" source: hosted - version: "0.13.4" + version: "0.13.5" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.0.2" icons_launcher: dependency: "direct dev" description: name: icons_launcher - url: "https://pub.dartlang.org" + sha256: f8ccfb80b56856b6eac586980bdd9c14f5ec24fb87127514055445ceb9424f4c + url: "https://pub.dev" source: hosted - version: "1.1.3" + version: "2.1.0" image: dependency: transitive description: name: image - url: "https://pub.dartlang.org" + sha256: "483a389d6ccb292b570c31b3a193779b1b0178e7eb571986d9a49904b6861227" + url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "4.0.15" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.5" json_annotation: dependency: transitive description: name: json_annotation - url: "https://pub.dartlang.org" + sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317 + url: "https://pub.dev" source: hosted - version: "4.5.0" - just_audio: - dependency: transitive - description: - name: just_audio - url: "https://pub.dartlang.org" - source: hosted - version: "0.9.20" - just_audio_platform_interface: - dependency: transitive - description: - name: just_audio_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "4.1.0" - just_audio_web: - dependency: transitive - description: - name: just_audio_web - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.7" - kplayer: - dependency: "direct main" - description: - name: kplayer - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.18" - kplayer_platform_interface: - dependency: transitive - description: - name: kplayer_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.12" - kplayer_with_audioplayers: - dependency: "direct main" - description: - name: kplayer_with_audioplayers - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.10" - kplayer_with_dart_vlc: - dependency: transitive - description: - name: kplayer_with_dart_vlc - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.10" - kplayer_with_just_audio: - dependency: transitive - description: - name: kplayer_with_just_audio - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.10" + version: "4.8.0" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "2.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" source: hosted - version: "0.12.11" + version: "0.12.13" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.1.4" + version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" source: hosted - version: "1.7.0" + version: "1.8.0" miniplayer: dependency: "direct main" description: @@ -344,107 +301,114 @@ packages: dependency: transitive description: name: nested - url: "https://pub.dartlang.org" + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" source: hosted version: "1.0.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" source: hosted - version: "1.8.1" + version: "1.8.2" path_provider: dependency: "direct main" description: name: path_provider - url: "https://pub.dartlang.org" + sha256: c7edf82217d4b2952b2129a61d3ad60f1075b9299e629e149a8d2e39c2e6aad4 + url: "https://pub.dev" source: hosted - version: "2.0.9" + version: "2.0.14" path_provider_android: dependency: transitive description: name: path_provider_android - url: "https://pub.dartlang.org" + sha256: da97262be945a72270513700a92b39dd2f4a54dad55d061687e2e37a6390366a + url: "https://pub.dev" source: hosted - version: "2.0.13" - path_provider_ios: + version: "2.0.25" + path_provider_foundation: dependency: transitive description: - name: path_provider_ios - url: "https://pub.dartlang.org" + name: path_provider_foundation + sha256: ad4c4d011830462633f03eb34445a45345673dfd4faf1ab0b4735fbd93b19183 + url: "https://pub.dev" source: hosted - version: "2.0.8" + version: "2.2.2" path_provider_linux: dependency: transitive description: name: path_provider_linux - url: "https://pub.dartlang.org" + sha256: "2ae08f2216225427e64ad224a24354221c2c7907e448e6e0e8b57b1eb9f10ad1" + url: "https://pub.dev" source: hosted - version: "2.1.5" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.5" + version: "2.1.10" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - url: "https://pub.dartlang.org" + sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" + url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.0.6" path_provider_windows: dependency: transitive description: name: path_provider_windows - url: "https://pub.dartlang.org" + sha256: f53720498d5a543f9607db4b0e997c4b5438884de25b0f73098cc2671a51b130 + url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.1.5" petitparser: dependency: transitive description: name: petitparser - url: "https://pub.dartlang.org" + sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4" + url: "https://pub.dev" source: hosted - version: "4.4.0" + version: "5.1.0" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" source: hosted version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + url: "https://pub.dev" + source: hosted + version: "3.7.3" process: dependency: transitive description: name: process - url: "https://pub.dartlang.org" + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" source: hosted version: "4.2.4" provider: dependency: "direct main" description: name: provider - url: "https://pub.dartlang.org" + sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + url: "https://pub.dev" source: hosted - version: "6.0.2" - rxdart: - dependency: transitive - description: - name: rxdart - url: "https://pub.dartlang.org" - source: hosted - version: "0.27.3" + version: "6.0.5" sky_engine: dependency: transitive description: flutter @@ -454,107 +418,130 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.0" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "33b31b6beb98100bf9add464a36a8dd03eb10c7a8cf15aeec535e9b054aaf04b" + url: "https://pub.dev" + source: hosted + version: "3.0.1" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" source: hosted - version: "0.4.9" + version: "0.4.16" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.3.1" universal_io: dependency: "direct main" description: name: universal_io - url: "https://pub.dartlang.org" + sha256: "06866290206d196064fd61df4c7aea1ffe9a4e7c4ccaa8fcded42dd41948005d" + url: "https://pub.dev" source: hosted - version: "2.0.4" + version: "2.2.0" uuid: dependency: transitive description: name: uuid - url: "https://pub.dartlang.org" + sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.0.7" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" win32: dependency: transitive description: name: win32 - url: "https://pub.dartlang.org" + sha256: a6f0236dbda0f63aa9a25ad1ff9a9d8a4eaaa5012da0dc59d21afdb1dc361ca4 + url: "https://pub.dev" source: hosted - version: "2.5.2" + version: "3.1.4" xdg_directories: dependency: transitive description: name: xdg_directories - url: "https://pub.dartlang.org" + sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 + url: "https://pub.dev" source: hosted - version: "0.2.0+1" + version: "1.0.0" xml: dependency: transitive description: name: xml - url: "https://pub.dartlang.org" + sha256: "979ee37d622dec6365e2efa4d906c37470995871fe9ae080d967e192d88286b5" + url: "https://pub.dev" source: hosted - version: "5.3.1" + version: "6.2.2" yaml: dependency: transitive description: name: yaml - url: "https://pub.dartlang.org" + sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" youtube_explode_dart: dependency: "direct main" description: name: youtube_explode_dart - url: "https://pub.dartlang.org" + sha256: "07889a6229a63e78f8d45a3b852897c2e0fa42e96c4daa38d411be211575bc38" + url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.12.4" sdks: - dart: ">=2.17.0-266.5.beta <3.0.0" - flutter: ">=2.8.1" + dart: ">=2.18.0 <3.0.0" + flutter: ">=3.3.0" diff --git a/pubspec.yaml b/pubspec.yaml index 439a56c..fb303e7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,8 +16,8 @@ dependencies: # url: https://git.p2p.legal/poka/youtube_explode.git # ref: master http: ^0.13.4 - kplayer: ^0.1.18 - kplayer_with_audioplayers: ^0.0.10 + # kplayer: ^0.1.18 + # kplayer_with_audioplayers: ^0.0.10 miniplayer: #^1.0.1 git: url: https://git.p2p.legal/poka/flutter_miniplayer.git @@ -26,13 +26,17 @@ dependencies: path_provider: ^2.0.9 universal_io: ^2.0.4 # ffmpeg_cli: ^0.1.0 - # audioplayers: ^1.0.0-rc.2 + audioplayers: ^4.0.1 + # git: + # url: https://github.com/bluefireteam/audioplayers/tree/main/packages/audioplayers_linux + # ref: main + dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^1.0.0 - icons_launcher: ^1.1.3 + flutter_lints: ^2.0.1 + icons_launcher: ^2.0.5 flutter_icons: android: true diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 7ffc1ef..09e8e2c 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,11 +7,8 @@ #include "generated_plugin_registrant.h" #include -#include void RegisterPlugins(flutter::PluginRegistry* registry) { AudioplayersWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); - DartVlcPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("DartVlcPlugin")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 2847f49..375535c 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,7 +4,6 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_windows - dart_vlc ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/windows/runner/CMakeLists.txt b/windows/runner/CMakeLists.txt index b9e550f..394917c 100644 --- a/windows/runner/CMakeLists.txt +++ b/windows/runner/CMakeLists.txt @@ -20,12 +20,20 @@ add_executable(${BINARY_NAME} WIN32 # that need different build settings. apply_standard_settings(${BINARY_NAME}) +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + # Disable Windows macros that collide with C++ standard library functions. target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") # Add dependency libraries and include directories. Add any application-specific # dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") # Run the Flutter tool portions of the build. This must not be removed. diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc index 1ce7fe6..ead8166 100644 --- a/windows/runner/Runner.rc +++ b/windows/runner/Runner.rc @@ -60,14 +60,14 @@ IDI_APP_ICON ICON "resources\\app_icon.ico" // Version // -#ifdef FLUTTER_BUILD_NUMBER -#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD #else -#define VERSION_AS_NUMBER 1,0,0 +#define VERSION_AS_NUMBER 1,0,0,0 #endif -#ifdef FLUTTER_BUILD_NAME -#define VERSION_AS_STRING #FLUTTER_BUILD_NAME +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION #else #define VERSION_AS_STRING "1.0.0" #endif @@ -93,7 +93,7 @@ BEGIN VALUE "FileDescription", "fipy" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "fipy" "\0" - VALUE "LegalCopyright", "Copyright (C) 2022 fipy.p2p. All rights reserved." "\0" + VALUE "LegalCopyright", "Copyright (C) 2023 fipy.p2p. All rights reserved." "\0" VALUE "OriginalFilename", "fipy.exe" "\0" VALUE "ProductName", "fipy" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" diff --git a/windows/runner/flutter_window.cpp b/windows/runner/flutter_window.cpp index b43b909..b25e363 100644 --- a/windows/runner/flutter_window.cpp +++ b/windows/runner/flutter_window.cpp @@ -26,6 +26,11 @@ bool FlutterWindow::OnCreate() { } RegisterPlugins(flutter_controller_->engine()); SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + return true; } diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp index e67b039..98f40d9 100644 --- a/windows/runner/main.cpp +++ b/windows/runner/main.cpp @@ -27,7 +27,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); - if (!window.CreateAndShow(L"fipy", origin, size)) { + if (!window.Create(L"fipy", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); diff --git a/windows/runner/resources/app_icon.ico b/windows/runner/resources/app_icon.ico index a1e320e..c04e20c 100644 Binary files a/windows/runner/resources/app_icon.ico and b/windows/runner/resources/app_icon.ico differ diff --git a/windows/runner/runner.exe.manifest b/windows/runner/runner.exe.manifest index c977c4a..a42ea76 100644 --- a/windows/runner/runner.exe.manifest +++ b/windows/runner/runner.exe.manifest @@ -7,7 +7,7 @@ - + diff --git a/windows/runner/win32_window.cpp b/windows/runner/win32_window.cpp index c10f08d..041a385 100644 --- a/windows/runner/win32_window.cpp +++ b/windows/runner/win32_window.cpp @@ -1,13 +1,31 @@ #include "win32_window.h" +#include #include #include "resource.h" namespace { +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + // The number of Win32Window objects that currently exist. static int g_active_window_count = 0; @@ -31,8 +49,8 @@ void EnableFullDpiSupportIfAvailable(HWND hwnd) { GetProcAddress(user32_module, "EnableNonClientDpiScaling")); if (enable_non_client_dpi_scaling != nullptr) { enable_non_client_dpi_scaling(hwnd); - FreeLibrary(user32_module); } + FreeLibrary(user32_module); } } // namespace @@ -102,9 +120,9 @@ Win32Window::~Win32Window() { Destroy(); } -bool Win32Window::CreateAndShow(const std::wstring& title, - const Point& origin, - const Size& size) { +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { Destroy(); const wchar_t* window_class = @@ -117,7 +135,7 @@ bool Win32Window::CreateAndShow(const std::wstring& title, double scale_factor = dpi / 96.0; HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, 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); @@ -126,9 +144,15 @@ bool Win32Window::CreateAndShow(const std::wstring& title, return false; } + UpdateTheme(window); + return OnCreate(); } +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + // static LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message, @@ -188,6 +212,10 @@ Win32Window::MessageHandler(HWND hwnd, SetFocus(child_content_); } return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; } return DefWindowProc(window_handle_, message, wparam, lparam); @@ -243,3 +271,18 @@ bool Win32Window::OnCreate() { void Win32Window::OnDestroy() { // No-op; provided for subclasses. } + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/windows/runner/win32_window.h b/windows/runner/win32_window.h index 17ba431..c86632d 100644 --- a/windows/runner/win32_window.h +++ b/windows/runner/win32_window.h @@ -28,15 +28,16 @@ class Win32Window { Win32Window(); virtual ~Win32Window(); - // Creates and shows a win32 window with |title| and position and size using + // Creates a win32 window with |title| that is positioned and sized 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); + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); // Release OS resources associated with window. void Destroy(); @@ -86,6 +87,9 @@ class Win32Window { // Retrieves a class instance pointer for |window| static Win32Window* GetThisFromHandle(HWND const window) noexcept; + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + bool quit_on_close_ = false; // window handle for top level window.