Change home titlebar to scrollable
This commit is contained in:
parent
a758c2d96d
commit
69d2568513
|
@ -25,6 +25,29 @@ void callbackDispatcher() {
|
|||
});
|
||||
}
|
||||
|
||||
ThemeData lightTheme = ThemeData(
|
||||
accentColorBrightness: Brightness.dark,
|
||||
primaryColor: Colors.grey[100],
|
||||
// accentColor: _accentSetColor,
|
||||
primaryColorLight: Colors.white,
|
||||
primaryColorDark: Colors.grey[300],
|
||||
dialogBackgroundColor: Colors.white,
|
||||
backgroundColor: Colors.grey[100],
|
||||
appBarTheme: AppBarTheme(
|
||||
color: Colors.grey[100],
|
||||
elevation: 0,
|
||||
),
|
||||
textTheme: TextTheme(
|
||||
bodyText2: TextStyle(fontSize: 15.0, fontWeight: FontWeight.normal),
|
||||
),
|
||||
tabBarTheme: TabBarTheme(
|
||||
labelColor: Colors.black,
|
||||
unselectedLabelColor: Colors.grey[400],
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
|
||||
class SettingState extends ChangeNotifier {
|
||||
KeyValueStorage themeStorage = KeyValueStorage(themesKey);
|
||||
KeyValueStorage accentStorage = KeyValueStorage(accentsKey);
|
||||
|
|
|
@ -12,80 +12,14 @@ import 'package:fluttertoast/fluttertoast.dart';
|
|||
|
||||
import '../../class/searchpodcast.dart';
|
||||
import '../../class/subscribe_podcast.dart';
|
||||
import '../../home/appbar/popupmenu.dart';
|
||||
import '../../util/context_extension.dart';
|
||||
import '../../webfeed/webfeed.dart';
|
||||
import '../../.env.dart';
|
||||
import '../nested_home.dart';
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
@override
|
||||
_MyHomePageState createState() => _MyHomePageState();
|
||||
}
|
||||
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
final _MyHomePageDelegate _delegate = _MyHomePageDelegate();
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
var _androidAppRetain = MethodChannel("android_app_retain");
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarIconBrightness:
|
||||
Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
// statusBarColor: Theme.of(context).primaryColor,
|
||||
),
|
||||
child: Scaffold(
|
||||
key: _scaffoldKey,
|
||||
appBar: AppBar(
|
||||
//elevation: 1.0,
|
||||
centerTitle: true,
|
||||
leading: IconButton(
|
||||
tooltip: 'Add',
|
||||
icon: const Icon(Icons.add_circle_outline),
|
||||
onPressed: () async {
|
||||
await showSearch<int>(
|
||||
context: context,
|
||||
delegate: _delegate,
|
||||
);
|
||||
},
|
||||
),
|
||||
title: Image(
|
||||
image: Theme.of(context).brightness == Brightness.light
|
||||
? AssetImage('assets/text.png')
|
||||
: AssetImage('assets/text_light.png'),
|
||||
height: 30,
|
||||
),
|
||||
actions: <Widget>[
|
||||
PopupMenu(),
|
||||
],
|
||||
),
|
||||
body: WillPopScope(
|
||||
onWillPop: () async {
|
||||
if (Platform.isAndroid) {
|
||||
_androidAppRetain.invokeMethod('sendToBackground');
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
child: Home(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _MyHomePageDelegate extends SearchDelegate<int> {
|
||||
class MyHomePageDelegate extends SearchDelegate<int> {
|
||||
final String searchFieldLabel;
|
||||
MyHomePageDelegate({this.searchFieldLabel})
|
||||
: super(searchFieldLabel: searchFieldLabel);
|
||||
static Future<List> getList(String searchText) async {
|
||||
String apiKey = environment['apiKey'];
|
||||
String url =
|
||||
|
@ -329,89 +263,6 @@ class _SearchResultState extends State<SearchResult>
|
|||
subscribeWorker.setSubscribeItem(item);
|
||||
}
|
||||
|
||||
// savePodcast(String rss) async {
|
||||
// if (mounted) setState(() => _adding = true);
|
||||
|
||||
// importOmpl.importState = ImportState.import;
|
||||
// try {
|
||||
// BaseOptions options = new BaseOptions(
|
||||
// connectTimeout: 30000,
|
||||
// receiveTimeout: 30000,
|
||||
// );
|
||||
// Response response = await Dio(options).get(rss);
|
||||
// var dbHelper = DBHelper();
|
||||
// String _realUrl = response.realUri.toString();
|
||||
|
||||
// bool _checkUrl = await dbHelper.checkPodcast(_realUrl);
|
||||
|
||||
// if (_checkUrl) {
|
||||
// if (mounted) setState(() => _issubscribe = true);
|
||||
|
||||
// var _p = RssFeed.parse(response.data);
|
||||
|
||||
// print(_p.title);
|
||||
|
||||
// var dir = await getApplicationDocumentsDirectory();
|
||||
|
||||
// Response<List<int>> imageResponse = await Dio().get<List<int>>(
|
||||
// _p.itunes.image.href,
|
||||
// options: Options(responseType: ResponseType.bytes));
|
||||
|
||||
// img.Image image = img.decodeImage(imageResponse.data);
|
||||
// img.Image thumbnail = img.copyResize(image, width: 300);
|
||||
|
||||
// String _uuid = Uuid().v4();
|
||||
// File("${dir.path}/$_uuid.png")
|
||||
// ..writeAsBytesSync(img.encodePng(thumbnail));
|
||||
|
||||
// String _imagePath = "${dir.path}/$_uuid.png";
|
||||
// String _primaryColor = await getColor(File("${dir.path}/$_uuid.png"));
|
||||
// String _author = _p.itunes.author ?? _p.author ?? '';
|
||||
// String _provider = _p.generator ?? '';
|
||||
// String _link = _p.link ?? '';
|
||||
// PodcastLocal podcastLocal = PodcastLocal(
|
||||
// _p.title,
|
||||
// _p.itunes.image.href,
|
||||
// _realUrl,
|
||||
// _primaryColor,
|
||||
// _author,
|
||||
// _uuid,
|
||||
// _imagePath,
|
||||
// _provider,
|
||||
// _link,
|
||||
// description: _p.description);
|
||||
// await groupList.subscribe(podcastLocal);
|
||||
|
||||
// if (_provider.contains('fireside')) {
|
||||
// FiresideData data = FiresideData(_uuid, _link);
|
||||
// await data.fatchData();
|
||||
// }
|
||||
|
||||
// importOmpl.importState = ImportState.parse;
|
||||
|
||||
// await dbHelper.savePodcastRss(_p, _uuid);
|
||||
// groupList.updatePodcast(podcastLocal.id);
|
||||
// importOmpl.importState = ImportState.complete;
|
||||
// } else {
|
||||
// importOmpl.importState = ImportState.error;
|
||||
// Fluttertoast.showToast(
|
||||
// msg: 'Podcast subscribed already',
|
||||
// gravity: ToastGravity.TOP,
|
||||
// );
|
||||
// await Future.delayed(Duration(seconds: 10));
|
||||
// importOmpl.importState = ImportState.stop;
|
||||
// }
|
||||
// } catch (e) {
|
||||
// importOmpl.importState = ImportState.error;
|
||||
// Fluttertoast.showToast(
|
||||
// msg: 'Network error, Subscribe failed',
|
||||
// gravity: ToastGravity.TOP,
|
||||
// );
|
||||
// await Future.delayed(Duration(seconds: 5));
|
||||
// importOmpl.importState = ImportState.stop;
|
||||
// }
|
||||
// }
|
||||
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart' hide NestedScrollView;
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tsacdop/class/download_state.dart';
|
||||
import 'package:tsacdop/class/podcast_group.dart';
|
||||
|
@ -21,6 +22,8 @@ import '../util/custompaint.dart';
|
|||
|
||||
import '../home/appbar/importompl.dart';
|
||||
import '../home/audioplayer.dart';
|
||||
import 'appbar/addpodcast.dart';
|
||||
import 'appbar/popupmenu.dart';
|
||||
import 'home_groups.dart';
|
||||
import 'download_list.dart';
|
||||
|
||||
|
@ -30,6 +33,10 @@ class Home extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
|
||||
final MyHomePageDelegate _delegate =
|
||||
MyHomePageDelegate(searchFieldLabel: 'Search podcast');
|
||||
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
TabController _controller;
|
||||
Decoration _getIndicator(BuildContext context) {
|
||||
return UnderlineTabIndicator(
|
||||
|
@ -41,6 +48,8 @@ class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
|
|||
));
|
||||
}
|
||||
|
||||
var _androidAppRetain = MethodChannel("android_app_retain");
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
@ -58,83 +67,134 @@ class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
|
|||
Widget build(BuildContext context) {
|
||||
double width = MediaQuery.of(context).size.width;
|
||||
double height = (width - 20) / 3 + 140;
|
||||
return SafeArea(
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Column(
|
||||
children: <Widget>[
|
||||
Import(),
|
||||
Expanded(
|
||||
child: NestedScrollView(
|
||||
innerScrollPositionKeyBuilder: () {
|
||||
return Key('tab' + _controller.index.toString());
|
||||
},
|
||||
pinnedHeaderSliverHeightBuilder: () => 50,
|
||||
headerSliverBuilder:
|
||||
(BuildContext context, bool innerBoxScrolled) {
|
||||
return <Widget>[
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int index) {
|
||||
return SizedBox(
|
||||
height: height,
|
||||
width: width,
|
||||
child: ScrollPodcasts(),
|
||||
);
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
systemNavigationBarIconBrightness:
|
||||
Theme.of(context).accentColorBrightness,
|
||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
),
|
||||
child: Scaffold(
|
||||
key: _scaffoldKey,
|
||||
body: WillPopScope(
|
||||
onWillPop: () async {
|
||||
if (Platform.isAndroid) {
|
||||
_androidAppRetain.invokeMethod('sendToBackground');
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
child: SafeArea(
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Column(
|
||||
children: <Widget>[
|
||||
Import(),
|
||||
Expanded(
|
||||
child: NestedScrollView(
|
||||
innerScrollPositionKeyBuilder: () {
|
||||
return Key('tab' + _controller.index.toString());
|
||||
},
|
||||
childCount: 1,
|
||||
),
|
||||
),
|
||||
SliverPersistentHeader(
|
||||
delegate: _SliverAppBarDelegate(
|
||||
TabBar(
|
||||
indicator: _getIndicator(context),
|
||||
isScrollable: true,
|
||||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
pinnedHeaderSliverHeightBuilder: () => 50,
|
||||
headerSliverBuilder:
|
||||
(BuildContext context, bool innerBoxScrolled) {
|
||||
return <Widget>[
|
||||
SliverToBoxAdapter(
|
||||
child: SizedBox(
|
||||
height: 50.0,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
IconButton(
|
||||
tooltip: 'Add',
|
||||
icon: const Icon(
|
||||
Icons.add_circle_outline),
|
||||
onPressed: () async {
|
||||
await showSearch<int>(
|
||||
context: context,
|
||||
delegate: _delegate,
|
||||
);
|
||||
},
|
||||
),
|
||||
Image(
|
||||
image: Theme.of(context).brightness ==
|
||||
Brightness.light
|
||||
? AssetImage('assets/text.png')
|
||||
: AssetImage(
|
||||
'assets/text_light.png'),
|
||||
height: 30,
|
||||
),
|
||||
PopupMenu(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int index) {
|
||||
return SizedBox(
|
||||
height: height,
|
||||
width: width,
|
||||
child: ScrollPodcasts(),
|
||||
);
|
||||
},
|
||||
childCount: 1,
|
||||
),
|
||||
),
|
||||
SliverPersistentHeader(
|
||||
delegate: _SliverAppBarDelegate(
|
||||
TabBar(
|
||||
indicator: _getIndicator(context),
|
||||
isScrollable: true,
|
||||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
controller: _controller,
|
||||
tabs: <Widget>[
|
||||
Tab(
|
||||
child: Text('Recent Update'),
|
||||
),
|
||||
Tab(
|
||||
child: Text('Favorite'),
|
||||
),
|
||||
Tab(
|
||||
child: Text('Download'),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
pinned: true,
|
||||
),
|
||||
];
|
||||
},
|
||||
body: TabBarView(
|
||||
controller: _controller,
|
||||
tabs: <Widget>[
|
||||
Tab(
|
||||
child: Text('Recent Update'),
|
||||
),
|
||||
Tab(
|
||||
child: Text('Favorite'),
|
||||
),
|
||||
Tab(
|
||||
child: Text('Download'),
|
||||
)
|
||||
children: <Widget>[
|
||||
NestedScrollViewInnerScrollPositionKeyWidget(
|
||||
Key('tab0'), _RecentUpdate()),
|
||||
NestedScrollViewInnerScrollPositionKeyWidget(
|
||||
Key('tab1'), _MyFavorite()),
|
||||
NestedScrollViewInnerScrollPositionKeyWidget(
|
||||
Key('tab2'), _MyDownload()),
|
||||
],
|
||||
),
|
||||
),
|
||||
pinned: true,
|
||||
),
|
||||
];
|
||||
},
|
||||
body: TabBarView(
|
||||
controller: _controller,
|
||||
children: <Widget>[
|
||||
NestedScrollViewInnerScrollPositionKeyWidget(
|
||||
Key('tab0'), _RecentUpdate()),
|
||||
NestedScrollViewInnerScrollPositionKeyWidget(
|
||||
Key('tab1'), _MyFavorite()),
|
||||
NestedScrollViewInnerScrollPositionKeyWidget(
|
||||
Key('tab2'), _MyDownload()),
|
||||
Selector<AudioPlayerNotifier, bool>(
|
||||
selector: (_, audio) => audio.playerRunning,
|
||||
builder: (_, data, __) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(bottom: data ? 60.0 : 0),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(child: PlayerWidget()),
|
||||
],
|
||||
),
|
||||
Selector<AudioPlayerNotifier, bool>(
|
||||
selector: (_, audio) => audio.playerRunning,
|
||||
builder: (_, data, __) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(bottom: data ? 60.0 : 0),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(child: PlayerWidget()),
|
||||
],
|
||||
),
|
||||
);
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -573,7 +633,7 @@ class _RecentUpdateState extends State<_RecentUpdate>
|
|||
),
|
||||
]),
|
||||
)
|
||||
: Center(child: CircularProgressIndicator());
|
||||
: Center();
|
||||
},
|
||||
);
|
||||
}
|
|
@ -40,6 +40,14 @@ class _ScrollPodcastsState extends State<ScrollPodcasts> {
|
|||
_groupIndex = 0;
|
||||
}
|
||||
|
||||
Widget _circleContainer(BuildContext context) => Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 10),
|
||||
height: 50,
|
||||
width: 50,
|
||||
decoration:
|
||||
BoxDecoration(shape: BoxShape.circle, color: context.primaryColor),
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
double _width = MediaQuery.of(context).size.width;
|
||||
|
@ -137,16 +145,49 @@ class _ScrollPodcastsState extends State<ScrollPodcasts> {
|
|||
),
|
||||
),
|
||||
Container(
|
||||
height: 70,
|
||||
color:
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
),
|
||||
height: 70,
|
||||
color:
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
_circleContainer(context),
|
||||
_circleContainer(context),
|
||||
_circleContainer(context)
|
||||
],
|
||||
)),
|
||||
],
|
||||
)),
|
||||
Container(
|
||||
height: (_width - 20) / 3 + 40,
|
||||
color: Theme.of(context).primaryColor,
|
||||
margin: EdgeInsets.symmetric(horizontal: 15),
|
||||
child: Center(
|
||||
child: _groupIndex == 0
|
||||
? Text.rich(TextSpan(
|
||||
style: context.textTheme.headline6
|
||||
.copyWith(height: 2),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'Welcome to Tsacdop\n',
|
||||
style: context.textTheme.headline6
|
||||
.copyWith(
|
||||
color: context.accentColor)),
|
||||
TextSpan(
|
||||
text: 'Get started\n',
|
||||
style: context.textTheme.headline6
|
||||
.copyWith(
|
||||
color: context.accentColor)),
|
||||
TextSpan(text: 'Tap '),
|
||||
WidgetSpan(
|
||||
child:
|
||||
Icon(Icons.add_circle_outline)),
|
||||
TextSpan(text: ' to subscribe podcasts')
|
||||
],
|
||||
))
|
||||
: Text('No podcast in this group',
|
||||
style: TextStyle(
|
||||
color: context.textTheme.bodyText2.color
|
||||
.withOpacity(0.5)))),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tsacdop/class/settingstate.dart';
|
||||
import 'package:tsacdop/home/appbar/addpodcast.dart';
|
||||
import 'package:tsacdop/home/home.dart';
|
||||
import 'package:tsacdop/util/pageroute.dart';
|
||||
import 'fourthpage.dart';
|
||||
import 'secondpage.dart';
|
||||
|
@ -209,7 +209,7 @@ class _SlideIntroState extends State<SlideIntro> {
|
|||
onTap: () {
|
||||
if (widget.goto == Goto.home) {
|
||||
Navigator.push(context,
|
||||
SlideLeftRoute(page: MyHomePage()));
|
||||
SlideLeftRoute(page: Home()));
|
||||
Provider.of<SettingState>(context,
|
||||
listen: false)
|
||||
.saveShowIntro();
|
||||
|
|
|
@ -4,12 +4,12 @@ import 'package:flutter/services.dart';
|
|||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
|
||||
import 'class/podcast_group.dart';
|
||||
import 'home/appbar/addpodcast.dart';
|
||||
import 'class/audiostate.dart';
|
||||
import 'class/settingstate.dart';
|
||||
import 'class/download_state.dart';
|
||||
import 'class/refresh_podcast.dart';
|
||||
import 'class/subscribe_podcast.dart';
|
||||
import 'home/home.dart';
|
||||
import 'intro_slider/app_intro.dart';
|
||||
|
||||
final SettingState themeSetting = SettingState();
|
||||
|
@ -20,14 +20,16 @@ Future main() async {
|
|||
runApp(
|
||||
MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider(create: (_) => themeSetting),
|
||||
ChangeNotifierProvider(
|
||||
create: (_) => themeSetting,
|
||||
),
|
||||
ChangeNotifierProvider(create: (_) => AudioPlayerNotifier()),
|
||||
ChangeNotifierProvider(create: (_) => GroupList()),
|
||||
ChangeNotifierProvider(create: (_) => SubscribeWorker()),
|
||||
ChangeNotifierProvider(create: (_) => RefreshWorker()),
|
||||
ChangeNotifierProvider(
|
||||
create: (_) => DownloadState(),
|
||||
),
|
||||
)
|
||||
],
|
||||
child: MyApp(),
|
||||
),
|
||||
|
@ -50,26 +52,8 @@ class MyApp extends StatelessWidget {
|
|||
themeMode: setting.theme,
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'Tsacdop',
|
||||
theme: ThemeData(
|
||||
accentColorBrightness: Brightness.dark,
|
||||
primaryColor: Colors.grey[100],
|
||||
theme: lightTheme.copyWith(
|
||||
accentColor: setting.accentSetColor,
|
||||
primaryColorLight: Colors.white,
|
||||
primaryColorDark: Colors.grey[300],
|
||||
dialogBackgroundColor: Colors.white,
|
||||
backgroundColor: Colors.grey[100],
|
||||
appBarTheme: AppBarTheme(
|
||||
color: Colors.grey[100],
|
||||
elevation: 0,
|
||||
),
|
||||
textTheme: TextTheme(
|
||||
bodyText2:
|
||||
TextStyle(fontSize: 15.0, fontWeight: FontWeight.normal),
|
||||
),
|
||||
tabBarTheme: TabBarTheme(
|
||||
labelColor: Colors.black,
|
||||
unselectedLabelColor: Colors.grey[400],
|
||||
),
|
||||
),
|
||||
darkTheme: ThemeData.dark().copyWith(
|
||||
accentColor: setting.accentSetColor,
|
||||
|
@ -80,7 +64,7 @@ class MyApp extends StatelessWidget {
|
|||
.copyWith(color: setting.realDark ? Colors.black87 : null),
|
||||
appBarTheme: AppBarTheme(elevation: 0),
|
||||
),
|
||||
home: setting.showIntro ? SlideIntro(goto: Goto.home) : MyHomePage(),
|
||||
home: setting.showIntro ? SlideIntro(goto: Goto.home) : Home(),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue