Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions apps/example/lib/pages/home_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:ap_common_example/pages/setting_page.dart';
import 'package:ap_common_example/pages/simple_example/simple_home_page.dart';
import 'package:ap_common_example/pages/study/course_page.dart';
import 'package:ap_common_example/pages/study/score_page.dart';
import 'package:ap_common_example/pages/tab_example/tab_home_page.dart';
import 'package:ap_common_example/pages/user_info_page.dart';
import 'package:ap_common_example/res/assets.dart';
import 'package:ap_common_example/utils/app_localizations.dart';
Expand Down Expand Up @@ -203,6 +204,13 @@ class HomePageState extends State<HomePage> {
const SimpleHomePage(),
),
),
DrawerMenuItem(
icon: Icons.tab,
title: 'Tab Navigation Example',
onTap: () => _openPage(
const TabHomePage(),
),
),
if (isLogin) ...<Widget>[
const DrawerDivider(),
DrawerMenuItem(
Expand Down
249 changes: 249 additions & 0 deletions apps/example/lib/pages/tab_example/tab_home_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
import 'package:ap_common/ap_common.dart';
import 'package:ap_common_example/pages/home_page.dart';
import 'package:ap_common_example/pages/school_info_page.dart';
import 'package:ap_common_example/pages/setting_page.dart';
import 'package:ap_common_example/pages/study/course_page.dart';
import 'package:ap_common_example/pages/study/score_page.dart';
import 'package:ap_common_example/res/assets.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

/// Demonstrates [HomePageScaffold] with bottom tab navigation
/// using [IndexedStack] and per-tab [Navigator]s.
class TabHomePage extends StatelessWidget {
const TabHomePage({super.key});

@override
Widget build(BuildContext context) {
return HomePageScaffold(
tabs: <HomeTab>[
HomeTab(
icon: Icon(ApIcon.home),
label: context.ap.home,
builder: (_) => const _HomeTab(),
),
HomeTab(
icon: Icon(ApIcon.classIcon),
label: context.ap.course,
builder: (_) => CoursePage(),
),
HomeTab(
icon: Icon(ApIcon.assignment),
label: context.ap.score,
builder: (_) => ScorePage(),
),
HomeTab(
icon: const Icon(Icons.more_horiz),
label: context.ap.otherInfo,
builder: (_) => const _MoreTab(),
),
],
);
}
}

// ─── Home Tab ─────────────────────────────────────────────

class _HomeTab extends StatefulWidget {
const _HomeTab();

@override
State<_HomeTab> createState() => _HomeTabState();
}

class _HomeTabState extends State<_HomeTab> {
HomeState state = HomeState.loading;
List<Announcement> announcements = <Announcement>[];
CourseData? courseData;

@override
void initState() {
super.initState();
_getAnnouncements();
_loadCourseData();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(context.ap.home),
automaticallyImplyLeading: false,
),
body: _buildBody(),
);
}

Widget _buildBody() {
switch (state) {
case HomeState.loading:
return const Center(
child: CircularProgressIndicator(),
);
case HomeState.finish:
return _buildContent();
case HomeState.error:
return HintContent(
icon: ApIcon.offlineBolt,
content: context.ap.somethingError,
);
case HomeState.empty:
return HintContent(
icon: ApIcon.offlineBolt,
content: context.ap.announcementEmpty,
);
case HomeState.offline:
return HintContent(
icon: ApIcon.offlineBolt,
content: context.ap.offlineMode,
);
}
}

Widget _buildContent() {
return ListView(
padding: const EdgeInsets.only(top: 8),
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
),
child: courseData != null
? TodayScheduleCard(
courseData: courseData!,
)
: EmptyScheduleCard(
message: context.ap.courseEmpty,
),
),
const SizedBox(height: 16),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
),
child: Text(
context.ap.announcements,
style: Theme.of(context).textTheme.titleMedium,
),
),
const SizedBox(height: 8),
...announcements.map(_buildAnnouncementTile),
],
);
}

Widget _buildAnnouncementTile(
Announcement announcement,
) {
return ListTile(
leading: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: SizedBox(
width: 56,
height: 56,
child: ApNetworkImage(
url: announcement.imgUrl,
),
),
),
title: Text(
announcement.title,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
onTap: () {
ApUtils.pushCupertinoStyle(
context,
AnnouncementContentPage(
announcement: announcement,
),
);
},
);
}

Future<void> _getAnnouncements() async {
final ApiResult<List<Announcement>> result =
await AnnouncementHelper.instance.getAnnouncements(tags: <String>[]);
switch (result) {
case ApiSuccess<List<Announcement>>(
:final List<Announcement> data,
):
announcements = data;
setState(() {
state = announcements.isEmpty ? HomeState.empty : HomeState.finish;
});
case ApiFailure<List<Announcement>>():
case ApiError<List<Announcement>>():
setState(() => state = HomeState.error);
}
}

Future<void> _loadCourseData() async {
final String rawString = await rootBundle.loadString(
FileAssets.courses,
);
setState(() {
courseData = CourseData.fromRawJson(rawString);
});
}
}

// ─── More Tab ─────────────────────────────────────────────

class _MoreTab extends StatelessWidget {
const _MoreTab();

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(context.ap.otherInfo),
automaticallyImplyLeading: false,
),
body: ListView(
children: <Widget>[
ListTile(
leading: Icon(ApIcon.info),
title: Text(context.ap.schoolInfo),
trailing: const Icon(
Icons.chevron_right,
),
onTap: () {
ApUtils.pushCupertinoStyle(
context,
SchoolInfoPage(),
);
},
),
ListTile(
leading: Icon(ApIcon.settings),
title: Text(context.ap.settings),
trailing: const Icon(
Icons.chevron_right,
),
onTap: () {
ApUtils.pushCupertinoStyle(
context,
SettingPage(),
);
},
),
ListTile(
leading: Icon(ApIcon.face),
title: Text(context.ap.about),
trailing: const Icon(
Icons.chevron_right,
),
onTap: () {
ApUtils.pushCupertinoStyle(
context,
HomePageState.aboutPage(context),
);
},
),
],
),
);
}
}
4 changes: 2 additions & 2 deletions apps/example/macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import Foundation
import file_saver
import file_selector_macos
import flutter_local_notifications
import gal
import google_sign_in_ios
import in_app_review
import package_info_plus
import photo_manager
import printing
import share_plus
import shared_preferences_foundation
Expand All @@ -23,10 +23,10 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FileSaverPlugin.register(with: registry.registrar(forPlugin: "FileSaverPlugin"))
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
GalPlugin.register(with: registry.registrar(forPlugin: "GalPlugin"))
FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin"))
InAppReviewPlugin.register(with: registry.registrar(forPlugin: "InAppReviewPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PhotoManagerPlugin.register(with: registry.registrar(forPlugin: "PhotoManagerPlugin"))
PrintingPlugin.register(with: registry.registrar(forPlugin: "PrintingPlugin"))
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
Expand Down
3 changes: 3 additions & 0 deletions apps/example/windows/flutter/generated_plugin_registrant.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <file_saver/file_saver_plugin.h>
#include <file_selector_windows/file_selector_windows.h>
#include <gal/gal_plugin_c_api.h>
#include <printing/printing_plugin.h>
#include <share_plus/share_plus_windows_plugin_c_api.h>
#include <url_launcher_windows/url_launcher_windows.h>
Expand All @@ -17,6 +18,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("FileSaverPlugin"));
FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows"));
GalPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("GalPluginCApi"));
PrintingPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PrintingPlugin"));
SharePlusWindowsPluginCApiRegisterWithRegistrar(
Expand Down
1 change: 1 addition & 0 deletions apps/example/windows/flutter/generated_plugins.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
file_saver
file_selector_windows
gal
printing
share_plus
url_launcher_windows
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export 'src/resources/ap_theme.dart';
export 'src/resources/resources.dart';
export 'src/scaffold/course_scaffold.dart';
export 'src/scaffold/home_page_scaffold.dart';
export 'src/scaffold/home_tab.dart';
export 'src/scaffold/image_viewer_scaffold.dart';
export 'src/scaffold/login_scaffold.dart';
export 'src/scaffold/score_scaffold.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,9 @@ class CourseScaffoldState extends State<CourseScaffold> {
child: const Icon(Icons.search),
),
],
SizedBox(
height: MediaQuery.of(context).viewPadding.bottom + 28.0,
),
],
),
),
Expand Down Expand Up @@ -646,8 +649,7 @@ class CourseScaffoldState extends State<CourseScaffold> {
}
final double pixelRatio =
MediaQuery.devicePixelRatioOf(context).clamp(2.0, 4.0);
final ui.Image image =
await boundary.toImage(pixelRatio: pixelRatio);
final ui.Image image = await boundary.toImage(pixelRatio: pixelRatio);
final ByteData? byteData =
await image.toByteData(format: ui.ImageByteFormat.png);
final DateTime now = DateTime.now();
Expand Down
Loading
Loading