Custom Window Titlebar support

This commit is contained in:
Kingkor Roy Tirtho 2022-01-05 19:17:11 +06:00
parent 619aa4af1a
commit 4d41b037e4
12 changed files with 219 additions and 110 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View File

@ -1,3 +1,4 @@
import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart' hide Page;
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
@ -122,6 +123,27 @@ class _HomeState extends State<Home> {
return Scaffold(
body: Column(
children: [
WindowTitleBarBox(
child: Row(
children: [
Expanded(
child: Row(
children: [
Container(
constraints: const BoxConstraints(maxWidth: 256),
color:
Theme.of(context).navigationRailTheme.backgroundColor,
child: MoveWindow(),
),
Expanded(child: MoveWindow())
],
)),
MinimizeWindowButton(animate: true),
MaximizeWindowButton(animate: true),
CloseWindowButton(animate: true),
],
),
),
Expanded(
child: Row(
children: [
@ -165,21 +187,25 @@ class _HomeState extends State<Home> {
builder: (context, snapshot) {
var avatarImg = snapshot.data?.images?.last.url;
return Padding(
padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (avatarImg != null)
CircleAvatar(
child: CachedNetworkImage(
imageUrl: avatarImg,
Row(
children: [
if (avatarImg != null)
CircleAvatar(
backgroundImage:
CachedNetworkImageProvider(avatarImg),
),
const SizedBox(width: 10),
Text(
snapshot.data?.displayName ?? "User's name",
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
),
Text(
snapshot.data?.displayName ?? "User's name",
style: const TextStyle(
fontWeight: FontWeight.bold,
),
],
),
IconButton(
icon: const Icon(Icons.settings_outlined),
@ -202,12 +228,15 @@ class _HomeState extends State<Home> {
if (_selectedIndex == 0)
Expanded(
child: Scrollbar(
child: PagedListView(
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<Category>(
itemBuilder: (context, item, index) {
return CategoryCard(item);
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: PagedListView(
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<Category>(
itemBuilder: (context, item, index) {
return CategoryCard(item);
},
),
),
),
),

View File

@ -0,0 +1,23 @@
import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:flutter/material.dart';
class PageWindowTitleBar extends StatelessWidget {
final Widget? leading;
final Widget? center;
const PageWindowTitleBar({Key? key, this.leading, this.center})
: super(key: key);
@override
Widget build(BuildContext context) {
return WindowTitleBarBox(
child: Row(
children: [
if (leading != null) leading!,
Expanded(child: MoveWindow(child: Center(child: center))),
MinimizeWindowButton(animate: true),
MaximizeWindowButton(animate: true),
CloseWindowButton(animate: true),
],
),
);
}
}

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/components/PageWindowTitleBar.dart';
import 'package:spotube/components/PlaylistCard.dart';
import 'package:spotube/provider/SpotifyDI.dart';
@ -24,19 +25,13 @@ class _PlaylistGenreViewState extends State<PlaylistGenreView> {
return Scaffold(
body: Column(
children: [
Row(
// mainAxisAlignment: MainAxisAlignment.center,
children: [
const BackButton(),
// genre name
Expanded(
child: Text(
widget.genreName,
style: Theme.of(context).textTheme.headline4,
textAlign: TextAlign.center,
),
),
],
const PageWindowTitleBar(
leading: BackButton(),
),
Text(
widget.genreName,
style: Theme.of(context).textTheme.headline4,
textAlign: TextAlign.center,
),
Consumer<SpotifyDI>(
builder: (context, data, child) => Expanded(

View File

@ -1,6 +1,5 @@
import 'dart:ui';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:spotube/components/PageWindowTitleBar.dart';
import 'package:spotube/helpers/zero-pad-num-str.dart';
import 'package:spotube/provider/Playback.dart';
import 'package:flutter/material.dart';
@ -98,42 +97,49 @@ class _PlaylistViewState extends State<PlaylistView> {
const TextStyle(fontWeight: FontWeight.bold, fontSize: 16);
return Column(
children: [
Row(
children: [
// nav back
const BackButton(),
// heart playlist
IconButton(
icon: const Icon(Icons.favorite_outline_rounded),
onPressed: () {},
),
// play playlist
Consumer<Playback>(builder: (context, playback, widget) {
var isPlaylistPlaying = playback.currentPlaylist?.id ==
this.widget.playlist.id;
return IconButton(
icon: Icon(
isPlaylistPlaying
? Icons.stop_rounded
: Icons.play_arrow_rounded,
),
onPressed: snapshot.hasData
? () {
if (!isPlaylistPlaying) {
playback.setCurrentPlaylist =
CurrentPlaylist(
tracks: tracks,
id: this.widget.playlist.id!,
name: this.widget.playlist.name!,
thumbnail:
this.widget.playlist.images![0].url!,
);
PageWindowTitleBar(
leading: Row(
children: [
// nav back
const BackButton(),
// heart playlist
IconButton(
icon: const Icon(Icons.favorite_outline_rounded),
onPressed: () {},
),
// play playlist
Consumer<Playback>(
builder: (context, playback, widget) {
var isPlaylistPlaying =
playback.currentPlaylist?.id ==
this.widget.playlist.id;
return IconButton(
icon: Icon(
isPlaylistPlaying
? Icons.stop_rounded
: Icons.play_arrow_rounded,
),
onPressed: snapshot.hasData
? () {
if (!isPlaylistPlaying) {
playback.setCurrentPlaylist =
CurrentPlaylist(
tracks: tracks,
id: this.widget.playlist.id!,
name: this.widget.playlist.name!,
thumbnail: this
.widget
.playlist
.images![0]
.url!,
);
}
}
}
: null,
);
}),
],
: null,
);
}),
],
),
),
Center(
child: Text(widget.playlist.name!,

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:spotube/components/PageWindowTitleBar.dart';
import 'package:spotube/provider/Auth.dart';
class Settings extends StatefulWidget {
@ -14,18 +15,16 @@ class _SettingsState extends State<Settings> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
elevation: 0,
iconTheme: Theme.of(context).iconTheme,
title: const Text(
"Settings",
),
centerTitle: true,
titleTextStyle: Theme.of(context).textTheme.headline4,
),
body: Column(
children: [
PageWindowTitleBar(
leading: const BackButton(),
center: Text(
"Settings",
style: Theme.of(context).textTheme.headline5,
),
),
const SizedBox(height: 10),
Builder(builder: (context) {
var auth = context.read<Auth>();
return ElevatedButton(

View File

@ -1,3 +1,4 @@
import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -10,6 +11,12 @@ import 'package:spotube/provider/SpotifyDI.dart';
void main() {
runApp(MyApp());
doWhenWindowReady(() {
appWindow.minSize = const Size(900, 700);
appWindow.alignment = Alignment.center;
appWindow.maximize();
appWindow.show();
});
}
class MyApp extends StatelessWidget {
@ -57,40 +64,46 @@ class MyApp extends StatelessWidget {
debugShowCheckedModeBanner: false,
title: 'Spotube',
theme: ThemeData(
primaryColor: Colors.greenAccent[400],
primarySwatch: Colors.green,
buttonTheme: const ButtonThemeData(
buttonColor: Colors.green,
),
textTheme: TextTheme(
bodyText1: TextStyle(color: Colors.grey[850]),
headline1: TextStyle(color: Colors.grey[850]),
headline2: TextStyle(color: Colors.grey[850]),
headline3: TextStyle(color: Colors.grey[850]),
headline4: TextStyle(color: Colors.grey[850]),
headline5: TextStyle(color: Colors.grey[850]),
headline6: TextStyle(color: Colors.grey[850]),
),
listTileTheme: ListTileThemeData(
iconColor: Colors.grey[850],
horizontalTitleGap: 0,
),
inputDecorationTheme: InputDecorationTheme(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.green[400]!,
width: 2.0,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey[800]!,
),
primaryColor: Colors.greenAccent[400],
primarySwatch: Colors.green,
buttonTheme: const ButtonThemeData(
buttonColor: Colors.green,
),
textTheme: TextTheme(
bodyText1: TextStyle(color: Colors.grey[850]),
headline1: TextStyle(color: Colors.grey[850]),
headline2: TextStyle(color: Colors.grey[850]),
headline3: TextStyle(color: Colors.grey[850]),
headline4: TextStyle(color: Colors.grey[850]),
headline5: TextStyle(color: Colors.grey[850]),
headline6: TextStyle(color: Colors.grey[850]),
),
listTileTheme: ListTileThemeData(
iconColor: Colors.grey[850],
horizontalTitleGap: 0,
),
inputDecorationTheme: InputDecorationTheme(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.green[400]!,
width: 2.0,
),
),
navigationRailTheme: NavigationRailThemeData(
backgroundColor: Colors.blueGrey[50],
)),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey[800]!,
),
),
),
navigationRailTheme: NavigationRailThemeData(
backgroundColor: Colors.blueGrey[50],
unselectedIconTheme:
IconThemeData(color: Colors.grey[850], opacity: 1),
unselectedLabelTextStyle: TextStyle(
color: Colors.grey[850],
),
),
),
home: const Home(),
),
);

View File

@ -6,9 +6,13 @@
#include "generated_plugin_registrant.h"
#include <bitsdojo_window_linux/bitsdojo_window_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) bitsdojo_window_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "BitsdojoWindowPlugin");
bitsdojo_window_plugin_register_with_registrar(bitsdojo_window_linux_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);

View File

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
bitsdojo_window_linux
url_launcher_linux
)

View File

@ -1,3 +1,4 @@
#include <bitsdojo_window_linux/bitsdojo_window_plugin.h>
#include "my_application.h"
#include <flutter_linux/flutter_linux.h>
@ -47,7 +48,9 @@ static void my_application_activate(GApplication* application) {
gtk_window_set_title(window, "spotube");
}
gtk_window_set_default_size(window, 1280, 720);
auto bdw = bitsdojo_window_from(window);
bdw->setCustomFrame(true);
// gtk_window_set_default_size(window, 1280, 720);
gtk_widget_show(GTK_WIDGET(window));
g_autoptr(FlDartProject) project = fl_dart_project_new();

View File

@ -8,6 +8,41 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.2"
bitsdojo_window:
dependency: "direct main"
description:
name: bitsdojo_window
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1+1"
bitsdojo_window_linux:
dependency: transitive
description:
name: bitsdojo_window_linux
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1"
bitsdojo_window_macos:
dependency: transitive
description:
name: bitsdojo_window_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
bitsdojo_window_platform_interface:
dependency: transitive
description:
name: bitsdojo_window_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
bitsdojo_window_windows:
dependency: transitive
description:
name: bitsdojo_window_windows
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
boolean_selector:
dependency: transitive
description:

View File

@ -44,6 +44,7 @@ dependencies:
youtube_explode_dart: ^1.10.8
mpv_dart: ^0.0.1
infinite_scroll_pagination: ^3.1.0
bitsdojo_window: ^0.1.1+1
dev_dependencies:
flutter_test: