Compare commits

...

22 Commits

Author SHA1 Message Date
LittleSheep
1d1d61d60c Merge pull request #1 from I21b/master 2025-02-15 23:40:05 +08:00
03c2491587 🔨 Add debian build scripts 2025-02-15 23:04:47 +08:00
2c1adc988c 🐛 Fix desktop window title 2025-02-15 22:25:23 +08:00
c0fbee55e4 🐛 Fix linux running issue 2025-02-15 21:22:22 +08:00
6e544c0b6c 🚀 Launch 2.3.2+69 2025-02-15 19:58:11 +08:00
7d56c5ef31 🐛 Fix reply / forward post type will follow the target post 2025-02-15 19:45:33 +08:00
c2df1af16d Reply & repost indicator 2025-02-15 19:43:41 +08:00
a8143c6453 🐛 Fix publisher list did not update after created 2025-02-15 19:23:02 +08:00
04065061e0 Leave realm 2025-02-15 19:20:34 +08:00
226eb452e5 Community and public chat, realm 2025-02-15 19:16:54 +08:00
a6715b0872 Chat return new line 2025-02-15 19:08:40 +08:00
43e3404dbb Delete publisher 2025-02-15 18:43:06 +08:00
c91cf7c813 🐛 Fix send empty message 2025-02-15 18:12:35 +08:00
92
9cd1cad695 Merge branch 'Solsynth:master' into master 2025-02-15 15:00:07 +09:00
92
dde280833b idk what to say 2025-02-15 14:59:45 +09:00
42ac12b53e 🔨 Fix linux build script 2025-02-15 13:48:25 +08:00
63567bf708 🔨 Fix linux build missing deps 2025-02-15 13:43:21 +08:00
5d3cadefef 🔨 Add linux build pipeline 2025-02-15 13:39:00 +08:00
251fbb2503 🐛 Try to fix github action build error 2025-02-15 13:34:23 +08:00
0b31d32217 💄 Fix some designs issue
🐛 Fix web some pages error
2025-02-15 13:06:25 +08:00
5ddd4fed2e 🐛 Fix missing new publisher button 2025-02-15 01:17:09 +08:00
48b6d5f6c1 🐛 Fix poll 2025-02-15 00:16:06 +08:00
32 changed files with 525 additions and 196 deletions

View File

@@ -39,3 +39,26 @@ jobs:
with:
name: build-output-windows
path: build/windows/x64/runner/Release
build-linux:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v4
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
cache: true
- run: |
sudo apt-get update -y
sudo apt-get install -y ninja-build libgtk-3-dev
sudo apt-get install libmpv-dev mpv
sudo apt-get install libayatana-appindicator3-dev
sudo apt-get install keybinder-3.0
- run: flutter pub get
- run: flutter build linux
- name: Archive production artifacts
uses: actions/upload-artifact@v4
with:
name: build-output-linux
path: build/linux/x64/release/bundle

View File

@@ -54,7 +54,7 @@ class CheckInWidget : GlanceAppWidget() {
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.registerTypeAdapter(Instant::class.java, InstantAdapter())
.create()
val resultTierSymbols = listOf("大凶", "", "中平", "", "大吉")
val resultTierSymbols = listOf("Bad", "Poor", "Medium", "Good", "Great")
val prefs = currentState.preferences
val checkInRaw: String? = prefs.getString("pas_check_in_record", null)
@@ -120,7 +120,7 @@ class CheckInWidget : GlanceAppWidget() {
}
Text(
text = "You haven't checked in today",
text = "You haven't divined today",
style = TextStyle(fontSize = 15.sp, color = GlanceTheme.colors.onSurface)
)
}

View File

@@ -5,7 +5,7 @@ meta {
}
post {
url: {{endpoint}}/cgi/id/dev/notify/1
url: {{endpoint}}/cgi/id/dev/notify/122
body: json
auth: inherit
}
@@ -15,12 +15,9 @@ body:json {
"client_id": "{{third_client_id}}",
"client_secret":"{{third_client_tk}}",
"type": "general",
"subject": "测试",
"subtitle": "Alphabot です",
"content": "全新通知动画",
"metadata": {
"image": "D2EDbcrsTugs3xk5"
},
"subject": "处理该帐号 @solian 的决定",
"subtitle": "违反用户协议",
"content": "您的帐号违反了我们用户协议中关于冒充我们官方的行为,至此做出停权的决定。还请见谅。该决定是最终决定,不接受上诉。",
"priority": 10
}
}

View File

@@ -15,7 +15,7 @@ body:json {
"client_id": "alphabot",
"client_secret": "_uR0sVnHTh",
"remark": "新年红包",
"amount": 9705,
"payee_id": 2
"amount": 150,
"payee_id": 18
}
}

View File

@@ -419,7 +419,7 @@
"callMessageEnded": "Call lasted {}",
"callMessageStarted": "Call started",
"dailyCheckIn": "Check In",
"dailyCheckInNone": "You haven't checked in today",
"dailyCheckInNone": "You haven't divined today",
"dailyCheckAction": "Check in right now!",
"dailyCheckDetail": "Can't understand the symbol? Master, help me understand it!",
"dailyCheckDetailTitle": "{}'s fortune details",
@@ -638,5 +638,17 @@
"pollVotes": {
"one": "{} vote",
"other": "{} votes"
}
},
"publisherDelete": "Delete Publisher {}",
"publisherDeleteDescription": "Are you sure you want to delete this publisher? This operation is irreversible.",
"channelIsPublic": "Public Channel",
"channelIsPublicDescription": "The channel is public, anyone can join.",
"channelIsCommunity": "Community Channel",
"channelIsCommunityDescription": "Currently, community channel has nothing special yet.",
"realmIsPublic": "Public Realm",
"realmIsPublicDescription": "The realm is public, anyone can join.",
"realmIsCommunity": "Community Realm",
"realmIsCommunityDescription": "Community realm will be displayed on the discover page.",
"realmLeave": "Leave Realm",
"realmLeaveDescription": "Leave the current realm and delete the realm's identity."
}

View File

@@ -637,5 +637,17 @@
"pollVotes": {
"one": "{} 票",
"other": "{} 票"
}
},
"publisherDelete": "删除发布者 {}",
"publisherDeleteDescription": "你确定要删除这个发布者吗?该操作不可撤销。",
"channelIsPublic": "公开频道",
"channelIsPublicDescription": "该频道是公开的,任何人都可以加入。",
"channelIsCommunity": "社区频道",
"channelIsCommunityDescription": "目前来说,社区频道还没有什么特别之处。",
"realmIsPublic": "公开领域",
"realmIsPublicDescription": "该领域是公开的,任何人都可以加入。",
"realmIsCommunity": "社区领域",
"realmIsCommunityDescription": "社区领域会显示在发现页面上。",
"realmLeave": "离开领域",
"realmLeaveDescription": "离开当前领域,并且删除领域中的身份。"
}

14
debian/debian.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
flutter_app:
command: surface
arch: x64
parent: /usr/local/lib
nonInteractive: false
control:
Package: solian
Version: 2.3.2
Architecture: amd64
Priority: optional
Depends: mpv keybinder-3.0
Maintainer: Solsynth LLC
Description: The Solar Network Desktop Application

9
debian/gui/surface.desktop vendored Normal file
View File

@@ -0,0 +1,9 @@
[Desktop Entry]
Version=2.3.2
Name=Solian
GenericName=Solian
Comment=The Solar Network Desktop Application
Terminal=false
Type=Application
Categories=Social Networking
Keywords=social;social network;chat;solar network

23
debian/gui/surface.svg vendored Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 232 KiB

View File

@@ -55,7 +55,7 @@ struct CheckInEntry: TimelineEntry {
struct CheckInWidgetEntryView : View {
var entry: CheckInProvider.Entry
private let resultTierSymbols: [String] = ["大凶", "", "中平", "", "大吉"]
private let resultTierSymbols: [String] = ["Bad", "Poor", "Medium", "Good", "Great"]
func checkIn() -> Void {}
@@ -91,7 +91,7 @@ struct CheckInWidgetEntryView : View {
} else {
VStack(alignment: .leading) {
Text("Check In").font(.system(size: 19, weight: .bold))
Text("You haven't check in today").font(.system(size: 15))
Text("You haven't divined today").font(.system(size: 15))
}.padding(.horizontal, 4)
Spacer()

View File

@@ -47,6 +47,8 @@ import 'package:tray_manager/tray_manager.dart';
import 'package:version/version.dart';
import 'package:workmanager/workmanager.dart';
import 'package:in_app_review/in_app_review.dart';
import 'package:image_picker_android/image_picker_android.dart';
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
@pragma('vm:entry-point')
void appBackgroundDispatcher() {
@@ -67,20 +69,6 @@ void appBackgroundDispatcher() {
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await EasyLocalization.ensureInitialized();
await Hive.initFlutter();
Hive.registerAdapter(SnChannelImplAdapter());
Hive.registerAdapter(SnRealmImplAdapter());
Hive.registerAdapter(SnChannelMemberImplAdapter());
Hive.registerAdapter(SnChatMessageImplAdapter());
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
GoRouter.optionURLReflectsImperativeAPIs = true;
usePathUrlStrategy();
if (!kIsWeb && (Platform.isWindows || Platform.isLinux || Platform.isMacOS)) {
doWhenWindowReady(() {
@@ -91,6 +79,23 @@ void main() async {
});
}
await EasyLocalization.ensureInitialized();
await Hive.initFlutter();
Hive.registerAdapter(SnChannelImplAdapter());
Hive.registerAdapter(SnRealmImplAdapter());
Hive.registerAdapter(SnChannelMemberImplAdapter());
Hive.registerAdapter(SnChatMessageImplAdapter());
if (kIsWeb && !Platform.isLinux) {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
}
GoRouter.optionURLReflectsImperativeAPIs = true;
usePathUrlStrategy();
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
Workmanager().initialize(
appBackgroundDispatcher,
@@ -107,6 +112,13 @@ void main() async {
}
}
if (!kIsWeb && Platform.isAndroid) {
final ImagePickerPlatform imagePickerImplementation = ImagePickerPlatform.instance;
if (imagePickerImplementation is ImagePickerAndroid) {
imagePickerImplementation.useAndroidPhotoPicker = true;
}
}
runApp(const SolianApp());
}
@@ -160,8 +172,8 @@ class SolianApp extends StatelessWidget {
),
),
breakpoints: [
const Breakpoint(start: 0, end: 450, name: MOBILE),
const Breakpoint(start: 451, end: 800, name: TABLET),
const Breakpoint(start: 0, end: 600, name: MOBILE),
const Breakpoint(start: 601, end: 800, name: TABLET),
const Breakpoint(start: 801, end: 1920, name: DESKTOP),
],
);

View File

@@ -42,22 +42,22 @@ class WebSocketProvider extends ChangeNotifier {
_connectCompleter = null;
}
_connectCompleter = Completer<void>();
if (!_ua.isAuthorized) return;
if (isConnected || conn != null) {
disconnect();
}
final atk = await _sn.getFreshAtk();
final uri = Uri.parse(
'${_sn.client.options.baseUrl.replaceFirst('http', 'ws')}/ws?tk=$atk',
);
isBusy = true;
notifyListeners();
try {
_connectCompleter = Completer<void>();
final atk = await _sn.getFreshAtk();
final uri = Uri.parse(
'${_sn.client.options.baseUrl.replaceFirst('http', 'ws')}/ws?tk=$atk',
);
isBusy = true;
notifyListeners();
conn = WebSocketChannel.connect(uri);
await conn!.ready;
_wsStream = conn!.stream.asBroadcastStream();
@@ -82,6 +82,7 @@ class WebSocketProvider extends ChangeNotifier {
isBusy = false;
notifyListeners();
_connectCompleter!.complete();
_connectCompleter = null;
}
}

View File

@@ -74,7 +74,10 @@ class _AbuseReportScreenState extends State<AbuseReportScreen> {
),
const Divider(height: 1),
if (_isBusy)
const CircularProgressIndicator().padding(all: 24).center()
Padding(
padding: const EdgeInsets.all(24),
child: const CircularProgressIndicator(),
).center()
else
Expanded(
child: ListView.builder(

View File

@@ -45,6 +45,33 @@ class _PublisherScreenState extends State<PublisherScreen> {
}
}
Future<void> _deletePublisher(SnPublisher publisher) async {
final confirm = await context.showConfirmDialog(
'publisherDelete'.tr(args: ['#${publisher.name}']),
'publisherDeleteDescription'.tr(),
);
if (!confirm) return;
if (!mounted) return;
setState(() => _isBusy = true);
try {
await context
.read<SnNetworkProvider>()
.client
.delete('/cgi/co/publishers/${publisher.name}');
if (!mounted) return;
context.showSnackbar('publisherDeleted'.tr(args: ['#${publisher.name}']));
_publishers.remove(publisher);
_fetchPublishers();
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
} finally {
setState(() => _isBusy = false);
}
}
@override
void initState() {
super.initState();
@@ -118,6 +145,18 @@ class _PublisherScreenState extends State<PublisherScreen> {
});
},
),
PopupMenuItem(
child: Row(
children: [
const Icon(Symbols.delete),
const Gap(16),
Text('delete').tr(),
],
),
onTap: () {
_deletePublisher(publisher);
},
),
],
),
);

View File

@@ -123,8 +123,10 @@ class _AlbumScreenState extends State<AlbumScreen> {
),
if (_isBusy)
SliverToBoxAdapter(
child:
const CircularProgressIndicator().padding(all: 24).center(),
child: Padding(
padding: const EdgeInsets.all(24),
child: const CircularProgressIndicator(),
).center(),
),
],
),

View File

@@ -37,6 +37,9 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
SnChannel? _editingChannel;
bool _isPublic = false;
bool _isCommunity = false;
Future<void> _fetchRealms() async {
setState(() => _isBusy = true);
try {
@@ -67,6 +70,8 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
_aliasController.text = _editingChannel!.alias;
_nameController.text = _editingChannel!.name;
_descriptionController.text = _editingChannel!.description;
_isPublic = _editingChannel!.isPublic;
_isCommunity = _editingChannel!.isCommunity;
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
@@ -88,6 +93,8 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
: uuid.v4().replaceAll('-', '').substring(0, 12),
'name': _nameController.text,
'description': _descriptionController.text,
'is_public': _isPublic,
'is_community': _isCommunity,
};
try {
@@ -271,6 +278,23 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
),
const Gap(12),
CheckboxListTile(
value: _isPublic,
title: Text('channelIsPublic'.tr()),
subtitle: Text('channelIsPublicDescription'.tr()),
onChanged: (value) {
setState(() => _isPublic = value ?? false);
},
),
CheckboxListTile(
value: _isCommunity,
title: Text('channelIsCommunity'.tr()),
subtitle: Text('channelIsCommunityDescription'.tr()),
onChanged: (value) {
setState(() => _isCommunity = value ?? false);
},
),
const Gap(12),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [

View File

@@ -131,6 +131,7 @@ class _HomeDashUpdateWidget extends StatelessWidget {
return Container(
padding: padding,
child: Card(
margin: EdgeInsets.zero,
child: ListTile(
leading: Icon(Symbols.update),
title: Text('updateAvailable').tr(),
@@ -180,6 +181,7 @@ class _HomeDashSpecialDayWidgetState extends State<_HomeDashSpecialDayWidget> {
return Column(
children: days.map((ele) {
return Card(
margin: EdgeInsets.zero,
child: ListTile(
leading: Text(kSpecialDaysSymbol[ele] ?? '🎉').fontSize(24),
title: Text('celebrate$ele').tr(args: [ua.user?.nick ?? 'user']),
@@ -203,6 +205,7 @@ class _HomeDashSpecialDayWidgetState extends State<_HomeDashSpecialDayWidget> {
final progress = dayz.getSpecialDayProgress(lastOne.$2, date);
final diff = nextOne.$2.difference(DateTime.now());
return Card(
margin: EdgeInsets.zero,
child: ListTile(
leading: Text(kSpecialDaysSymbol[name] ?? '🎉').fontSize(24),
title: Text('pending$name').tr(args: [RelativeTime(context).format(date).replaceFirst('in', '').trim()]),
@@ -270,6 +273,7 @@ class _HomeDashTodayNewsState extends State<_HomeDashTodayNews> {
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.zero,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -469,6 +473,7 @@ class _HomeDashCheckInWidgetState extends State<_HomeDashCheckInWidget> {
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.zero,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -594,6 +599,7 @@ class _HomeDashNotificationWidgetState extends State<_HomeDashNotificationWidget
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.zero,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -667,11 +673,13 @@ class _HomeDashRecommendationPostWidgetState extends State<_HomeDashRecommendati
Widget build(BuildContext context) {
if (_isBusy) {
return Card(
margin: EdgeInsets.zero,
child: CircularProgressIndicator().center(),
);
}
return Card(
margin: EdgeInsets.zero,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [

View File

@@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_context_menu/flutter_context_menu.dart';
import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart';
import 'package:hotkey_manager/hotkey_manager.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:pasteboard/pasteboard.dart';
@@ -110,7 +111,7 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
final HotKey _pasteHotKey = HotKey(
key: PhysicalKeyboardKey.keyV,
modifiers: [Platform.isMacOS ? HotKeyModifier.meta : HotKeyModifier.control],
modifiers: [(!kIsWeb && Platform.isMacOS) ? HotKeyModifier.meta : HotKeyModifier.control],
scope: HotKeyScope.inapp,
);
@@ -136,6 +137,9 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
builder: (context) => _PostPublisherPopup(
controller: _writeController,
publishers: _publishers,
onUpdate: () {
_fetchPublishers();
},
),
);
}
@@ -160,7 +164,9 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
@override
void dispose() {
_writeController.dispose();
if (!kIsWeb && !(Platform.isAndroid || Platform.isIOS)) hotKeyManager.unregister(_pasteHotKey);
if (!kIsWeb && !(Platform.isAndroid || Platform.isIOS)) {
hotKeyManager.unregister(_pasteHotKey);
}
super.dispose();
}
@@ -250,6 +256,62 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
],
),
),
if (_writeController.replyingPost != null)
Container(
padding: const EdgeInsets.only(top: 4, bottom: 4, left: 20, right: 20),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Theme.of(context).dividerColor,
width: 1 / MediaQuery.of(context).devicePixelRatio,
),
),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(Symbols.reply, size: 16),
const Gap(10),
Text('@${_writeController.replyingPost!.publisher.name}').bold(),
const Gap(4),
Expanded(
child: Text(
_writeController.replyingPost!.body['content'],
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
if (_writeController.repostingPost != null)
Container(
padding: const EdgeInsets.only(top: 4, bottom: 4, left: 20, right: 20),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Theme.of(context).dividerColor,
width: 1 / MediaQuery.of(context).devicePixelRatio,
),
),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(Symbols.forward, size: 16),
const Gap(10),
Text('@${_writeController.repostingPost!.publisher.name}').bold(),
const Gap(4),
Expanded(
child: Text(
_writeController.repostingPost!.body['content'],
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
Expanded(
child: Stack(
children: [
@@ -434,8 +496,9 @@ class _PostEditorActionScrollBehavior extends MaterialScrollBehavior {
class _PostPublisherPopup extends StatelessWidget {
final PostWriteController controller;
final List<SnPublisher>? publishers;
final Function onUpdate;
const _PostPublisherPopup({required this.controller, this.publishers});
const _PostPublisherPopup({required this.controller, this.publishers, required this.onUpdate});
@override
Widget build(BuildContext context) {
@@ -450,6 +513,20 @@ class _PostPublisherPopup extends StatelessWidget {
Text('accountPublishers', style: Theme.of(context).textTheme.titleLarge).tr(),
],
).padding(horizontal: 20, top: 16, bottom: 12),
ListTile(
leading: const Icon(Symbols.add),
title: Text('publishersNew').tr(),
subtitle: Text('publisherNewSubtitle').tr(),
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
onTap: () {
GoRouter.of(context).pushNamed('accountPublisherNew').then((value) {
if (value == true) {
onUpdate();
}
});
},
),
const Divider(height: 1),
Expanded(
child: ListView.builder(
itemCount: publishers?.length ?? 0,

View File

@@ -50,6 +50,8 @@ class _RealmManageScreenState extends State<RealmManageScreen> {
_aliasController.text = out.alias;
_nameController.text = out.name;
_descriptionController.text = out.description;
_isPublic = out.isPublic;
_isCommunity = out.isCommunity;
} catch (err) {
// ignore: use_build_context_synchronously
if (context.mounted) context.showErrorDialog(err);
@@ -67,6 +69,9 @@ class _RealmManageScreenState extends State<RealmManageScreen> {
final _imagePicker = ImagePicker();
bool _isPublic = false;
bool _isCommunity = false;
Future<void> _updateImage(String place) async {
final image = await _imagePicker.pickImage(source: ImageSource.gallery);
if (image == null) return;
@@ -138,6 +143,8 @@ class _RealmManageScreenState extends State<RealmManageScreen> {
'description': _descriptionController.text,
'avatar': _avatar,
'banner': _banner,
'is_public': _isPublic,
'is_community': _isCommunity,
};
try {
@@ -293,6 +300,23 @@ class _RealmManageScreenState extends State<RealmManageScreen> {
FocusManager.instance.primaryFocus?.unfocus(),
),
const Gap(12),
CheckboxListTile(
value: _isPublic,
title: Text('realmIsPublic'.tr()),
subtitle: Text('realmIsPublicDescription'.tr()),
onChanged: (value) {
setState(() => _isPublic = value ?? false);
},
),
CheckboxListTile(
value: _isCommunity,
title: Text('realmIsCommunity'.tr()),
subtitle: Text('realmIsCommunityDescription'.tr()),
onChanged: (value) {
setState(() => _isCommunity = value ?? false);
},
),
const Gap(12),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [

View File

@@ -357,6 +357,28 @@ class _RealmSettingsWidgetState extends State<_RealmSettingsWidget> {
}
}
Future<void> _leaveRealm() async {
final confirm = await context.showConfirmDialog(
'realmLeave'.tr(),
'realmLeaveDescription'.tr(),
);
if (!confirm) return;
if (!mounted) return;
final sn = context.read<SnNetworkProvider>();
try {
await sn.client.delete('/cgi/id/realms/${widget.realm!.alias}/members/me');
if (!mounted) return;
Navigator.pop(context, true);
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
} finally {
setState(() => _isBusy = false);
}
}
@override
Widget build(BuildContext context) {
final ua = context.read<UserProvider>();
@@ -367,22 +389,31 @@ class _RealmSettingsWidgetState extends State<_RealmSettingsWidget> {
children: [
const Gap(8),
ListTile(
leading: const Icon(Symbols.edit),
leading: const Icon(Symbols.logout),
trailing: const Icon(Symbols.chevron_right),
title: Text('realmEdit').tr(),
subtitle: Text('realmEditDescription').tr(),
title: Text('realmLeave').tr(),
subtitle: Text('realmLeaveDescription').tr(),
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
onTap: () {
GoRouter.of(context).pushNamed(
'realmManage',
queryParameters: {'editing': widget.realm!.alias},
).then((value) {
if (value != null) {
widget.onUpdate();
}
});
},
onTap: _isBusy ? null : () => _leaveRealm(),
),
if (isOwned)
ListTile(
leading: const Icon(Symbols.edit),
trailing: const Icon(Symbols.chevron_right),
title: Text('realmEdit').tr(),
subtitle: Text('realmEditDescription').tr(),
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
onTap: () {
GoRouter.of(context).pushNamed(
'realmManage',
queryParameters: {'editing': widget.realm!.alias},
).then((value) {
if (value != null) {
widget.onUpdate();
}
});
},
),
if (isOwned)
ListTile(
leading: const Icon(Symbols.delete),

View File

@@ -154,7 +154,7 @@ class _RealmJoinPopupState extends State<_RealmJoinPopup> {
try {
setState(() => _isBusy = true);
final sn = context.read<SnNetworkProvider>();
final resp = await sn.client.get('/cgi/im/channels/${widget.realm.alias}');
final resp = await sn.client.get('/cgi/im/channels/${widget.realm.alias}/public');
final out = List<SnChannel>.from(
resp.data.map((e) => SnChannel.fromJson(e)).cast<SnChannel>(),
);

View File

@@ -3,7 +3,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'check_in.freezed.dart';
part 'check_in.g.dart';
const List<String> kCheckInResultTierSymbols = ['大凶', '', '中平', '', '大吉'];
const List<String> kCheckInResultTierSymbols = ['Bad', 'Poor', 'Medium', 'Good', 'Great'];
@freezed
class SnCheckInRecord with _$SnCheckInRecord {

View File

@@ -16,8 +16,7 @@ class SnPoll with _$SnPoll {
required SnPollMetric metric,
}) = _SnPoll;
factory SnPoll.fromJson(Map<String, Object?> json) =>
_$SnPollFromJson(json);
factory SnPoll.fromJson(Map<String, Object?> json) => _$SnPollFromJson(json);
}
@freezed
@@ -25,11 +24,11 @@ class SnPollMetric with _$SnPollMetric {
const factory SnPollMetric({
required int totalAnswer,
@Default({}) Map<String, int> byOptions,
@Default({}) Map<String, int> byOptionsPercentage,
@Default({}) Map<String, double> byOptionsPercentage,
}) = _SnPollMetric;
factory SnPollMetric.fromJson(Map<String, Object?> json)
=> _$SnPollMetricFromJson(json);
factory SnPollMetric.fromJson(Map<String, Object?> json) =>
_$SnPollMetricFromJson(json);
}
@freezed
@@ -41,6 +40,6 @@ class SnPollOption with _$SnPollOption {
required String description,
}) = _SnPollOption;
factory SnPollOption.fromJson(Map<String, Object?> json)
=> _$SnPollOptionFromJson(json);
factory SnPollOption.fromJson(Map<String, Object?> json) =>
_$SnPollOptionFromJson(json);
}

View File

@@ -345,7 +345,7 @@ SnPollMetric _$SnPollMetricFromJson(Map<String, dynamic> json) {
mixin _$SnPollMetric {
int get totalAnswer => throw _privateConstructorUsedError;
Map<String, int> get byOptions => throw _privateConstructorUsedError;
Map<String, int> get byOptionsPercentage =>
Map<String, double> get byOptionsPercentage =>
throw _privateConstructorUsedError;
/// Serializes this SnPollMetric to a JSON map.
@@ -367,7 +367,7 @@ abstract class $SnPollMetricCopyWith<$Res> {
$Res call(
{int totalAnswer,
Map<String, int> byOptions,
Map<String, int> byOptionsPercentage});
Map<String, double> byOptionsPercentage});
}
/// @nodoc
@@ -401,7 +401,7 @@ class _$SnPollMetricCopyWithImpl<$Res, $Val extends SnPollMetric>
byOptionsPercentage: null == byOptionsPercentage
? _value.byOptionsPercentage
: byOptionsPercentage // ignore: cast_nullable_to_non_nullable
as Map<String, int>,
as Map<String, double>,
) as $Val);
}
}
@@ -417,7 +417,7 @@ abstract class _$$SnPollMetricImplCopyWith<$Res>
$Res call(
{int totalAnswer,
Map<String, int> byOptions,
Map<String, int> byOptionsPercentage});
Map<String, double> byOptionsPercentage});
}
/// @nodoc
@@ -449,7 +449,7 @@ class __$$SnPollMetricImplCopyWithImpl<$Res>
byOptionsPercentage: null == byOptionsPercentage
? _value._byOptionsPercentage
: byOptionsPercentage // ignore: cast_nullable_to_non_nullable
as Map<String, int>,
as Map<String, double>,
));
}
}
@@ -460,7 +460,7 @@ class _$SnPollMetricImpl implements _SnPollMetric {
const _$SnPollMetricImpl(
{required this.totalAnswer,
final Map<String, int> byOptions = const {},
final Map<String, int> byOptionsPercentage = const {}})
final Map<String, double> byOptionsPercentage = const {}})
: _byOptions = byOptions,
_byOptionsPercentage = byOptionsPercentage;
@@ -478,10 +478,10 @@ class _$SnPollMetricImpl implements _SnPollMetric {
return EqualUnmodifiableMapView(_byOptions);
}
final Map<String, int> _byOptionsPercentage;
final Map<String, double> _byOptionsPercentage;
@override
@JsonKey()
Map<String, int> get byOptionsPercentage {
Map<String, double> get byOptionsPercentage {
if (_byOptionsPercentage is EqualUnmodifiableMapView)
return _byOptionsPercentage;
// ignore: implicit_dynamic_type
@@ -534,7 +534,7 @@ abstract class _SnPollMetric implements SnPollMetric {
const factory _SnPollMetric(
{required final int totalAnswer,
final Map<String, int> byOptions,
final Map<String, int> byOptionsPercentage}) = _$SnPollMetricImpl;
final Map<String, double> byOptionsPercentage}) = _$SnPollMetricImpl;
factory _SnPollMetric.fromJson(Map<String, dynamic> json) =
_$SnPollMetricImpl.fromJson;
@@ -544,7 +544,7 @@ abstract class _SnPollMetric implements SnPollMetric {
@override
Map<String, int> get byOptions;
@override
Map<String, int> get byOptionsPercentage;
Map<String, double> get byOptionsPercentage;
/// Create a copy of SnPollMetric
/// with the given fields replaced by the non-null parameter values.

View File

@@ -40,7 +40,7 @@ _$SnPollMetricImpl _$$SnPollMetricImplFromJson(Map<String, dynamic> json) =>
const {},
byOptionsPercentage:
(json['by_options_percentage'] as Map<String, dynamic>?)?.map(
(k, e) => MapEntry(k, (e as num).toInt()),
(k, e) => MapEntry(k, (e as num).toDouble()),
) ??
const {},
);

View File

@@ -45,7 +45,12 @@ class ChatMessageInputState extends State<ChatMessageInput> {
final HotKey _pasteHotKey = HotKey(
key: PhysicalKeyboardKey.keyV,
modifiers: [Platform.isMacOS ? HotKeyModifier.meta : HotKeyModifier.control],
modifiers: [(!kIsWeb && Platform.isMacOS) ? HotKeyModifier.meta : HotKeyModifier.control],
scope: HotKeyScope.inapp,
);
final HotKey _newLineHotKey = HotKey(
key: PhysicalKeyboardKey.enter,
modifiers: [(!kIsWeb && Platform.isMacOS) ? HotKeyModifier.meta : HotKeyModifier.control],
scope: HotKeyScope.inapp,
);
@@ -61,6 +66,10 @@ class ChatMessageInputState extends State<ChatMessageInput> {
));
setState(() {});
});
hotKeyManager.register(_newLineHotKey, keyDownHandler: (_) async {
if (_contentController.text.isEmpty) return;
_contentController.text += '\n';
});
}
@override
@@ -112,6 +121,7 @@ class ChatMessageInputState extends State<ChatMessageInput> {
}
Future<void> _sendMessage() async {
if (_contentController.text.isEmpty && _attachments.isEmpty) return;
if (_isBusy) return;
final attach = context.read<SnAttachmentProvider>();
@@ -204,7 +214,10 @@ class ChatMessageInputState extends State<ChatMessageInput> {
_contentController.dispose();
_focusNode.dispose();
_dismissEmojiPicker();
if (!kIsWeb && !(Platform.isAndroid || Platform.isIOS)) hotKeyManager.unregister(_pasteHotKey);
if (!kIsWeb && !(Platform.isAndroid || Platform.isIOS)) {
hotKeyManager.unregister(_pasteHotKey);
hotKeyManager.unregister(_newLineHotKey);
}
super.dispose();
}
@@ -344,6 +357,7 @@ class ChatMessageInputState extends State<ChatMessageInput> {
_sendMessage();
_focusNode.requestFocus();
},
maxLines: null,
),
),
const Gap(8),

View File

@@ -166,10 +166,12 @@ class AppRootScaffold extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: Platform.isMacOS ? MainAxisAlignment.center : MainAxisAlignment.start,
children: [
Text(
'Solar Network',
style: GoogleFonts.spaceGrotesk(),
).padding(horizontal: 12, vertical: 5),
Expanded(
child: Text(
'Solar Network',
style: GoogleFonts.spaceGrotesk(),
).padding(horizontal: 12, vertical: 5),
),
if (!Platform.isMacOS)
Row(
mainAxisSize: MainAxisSize.min,

View File

@@ -965,7 +965,7 @@ class _PostContentHeader extends StatelessWidget {
onTap: () {
GoRouter.of(context).pushNamed(
'postEditor',
pathParameters: {'mode': data.typePlural},
pathParameters: {'mode': 'stories'},
queryParameters: {'replying': data.id.toString()},
);
},
@@ -981,7 +981,7 @@ class _PostContentHeader extends StatelessWidget {
onTap: () {
GoRouter.of(context).pushNamed(
'postEditor',
pathParameters: {'mode': data.typePlural},
pathParameters: {'mode': 'stories'},
queryParameters: {'reposting': data.id.toString()},
);
},

View File

@@ -31,19 +31,27 @@ class _PostPollState extends State<PostPoll> {
String? _answeredChoice;
Future<void> _refreshPoll() async {
final sn = context.read<SnNetworkProvider>();
final resp = await sn.client.get('/cgi/co/polls/${widget.poll.id}');
if (!mounted) return;
setState(() => _poll = SnPoll.fromJson(resp.data!));
}
Future<void> _fetchAnswer() async {
final ua = context.read<UserProvider>();
if (!ua.isAuthorized) return;
try {
setState(() => _isBusy = true);
final sn = context.read<SnNetworkProvider>();
final resp = await sn.client.get('/cgi/co/polls/${widget.poll.id}/answer');
final resp =
await sn.client.get('/cgi/co/polls/${widget.poll.id}/answer');
_answeredChoice = resp.data?['answer'];
if (!mounted) return;
setState(() {});
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
// ignore because it may not found
} finally {
setState(() => _isBusy = false);
}
@@ -59,8 +67,9 @@ class _PostPollState extends State<PostPoll> {
'answer': option.id,
});
if (!mounted) return;
context.showSnackbar('pollAnswered'.tr());
HapticFeedback.heavyImpact();
_answeredChoice = option.id;
_refreshPoll();
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
@@ -78,15 +87,24 @@ class _PostPollState extends State<PostPoll> {
for (final option in _poll.options)
Stack(
children: [
Container(
height: 60,
width: MediaQuery.of(context).size.width * (_poll.metric.byOptionsPercentage[option.id] ?? 0).toDouble(),
color: Theme.of(context).colorScheme.surfaceContainerHigh,
ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(8)),
child: Container(
height: 60,
width: MediaQuery.of(context).size.width *
(_poll.metric.byOptionsPercentage[option.id] ?? 0)
.toDouble(),
color: Theme.of(context).colorScheme.surfaceContainerHigh,
),
),
ListTile(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
minTileHeight: 60,
leading: _answeredChoice == option.id ? const Icon(Symbols.circle, fill: 1) : const Icon(Symbols.circle),
leading: _answeredChoice == option.id
? const Icon(Symbols.circle, fill: 1)
: const Icon(Symbols.circle),
title: Text(option.name),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -95,14 +113,18 @@ class _PostPollState extends State<PostPoll> {
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text('pollVotes'.plural(_poll.metric.byOptions[option.id] ?? 0)),
Text(
'pollVotes'
.plural(_poll.metric.byOptions[option.id] ?? 0),
),
Text(' · ').padding(horizontal: 4),
Text(
'${((_poll.metric.byOptionsPercentage[option.id] ?? 0).toDouble() * 100).toStringAsFixed(2)}%',
),
],
),
if (option.description.isNotEmpty) Text(option.description),
if (option.description.isNotEmpty)
Text(option.description),
],
),
onTap: _isBusy ? null : () => _voteForOption(option),

View File

@@ -1,6 +1,5 @@
#include "my_application.h"
#include <bitsdojo_window_linux/bitsdojo_window_plugin.h>
#include "my_application.h"
#include <flutter_linux/flutter_linux.h>
#ifdef GDK_WINDOWING_X11
@@ -42,15 +41,16 @@ static void my_application_activate(GApplication* application) {
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, "Surface");
gtk_header_bar_set_title(header_bar, "bitsdojo_window_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, "Surface");
gtk_window_set_title(window, "bitsdojo_window_example");
}
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();
@@ -84,24 +84,6 @@ static gboolean my_application_local_command_line(GApplication* application, gch
return TRUE;
}
// Implements GApplication::startup.
static void my_application_startup(GApplication* application) {
//MyApplication* self = MY_APPLICATION(object);
// Perform any actions required at application startup.
G_APPLICATION_CLASS(my_application_parent_class)->startup(application);
}
// Implements GApplication::shutdown.
static void my_application_shutdown(GApplication* application) {
//MyApplication* self = MY_APPLICATION(object);
// Perform any actions required at application shutdown.
G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application);
}
// Implements GObject::dispose.
static void my_application_dispose(GObject* object) {
MyApplication* self = MY_APPLICATION(object);
@@ -112,8 +94,6 @@ static void my_application_dispose(GObject* 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_APPLICATION_CLASS(klass)->startup = my_application_startup;
G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown;
G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
}

View File

@@ -66,10 +66,10 @@ packages:
dependency: transitive
description:
name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
url: "https://pub.dev"
source: hosted
version: "2.11.0"
version: "2.12.0"
bitsdojo_window:
dependency: "direct main"
description:
@@ -114,10 +114,10 @@ packages:
dependency: transitive
description:
name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "2.1.2"
build:
dependency: transitive
description:
@@ -226,10 +226,10 @@ packages:
dependency: transitive
description:
name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.4.0"
checked_yaml:
dependency: transitive
description:
@@ -250,10 +250,10 @@ packages:
dependency: transitive
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.1.2"
code_builder:
dependency: transitive
description:
@@ -266,10 +266,10 @@ packages:
dependency: "direct main"
description:
name: collection
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.0"
version: "1.19.1"
connectivity_plus:
dependency: transitive
description:
@@ -354,10 +354,10 @@ packages:
dependency: "direct main"
description:
name: dart_webrtc
sha256: "3b3ff59c66cbc1577ed0f28d7005b5163555208fb1697a42207424ab8baa27c5"
sha256: "03df5b41b23bc185ebcf4b0ffc92d002e295bf56287fb5f9d2c321ddaf7760cc"
url: "https://pub.dev"
source: hosted
version: "1.5.0"
version: "1.5.1"
dbus:
dependency: transitive
description:
@@ -474,10 +474,10 @@ packages:
dependency: transitive
description:
name: fake_async
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
version: "1.3.2"
ffi:
dependency: transitive
description:
@@ -498,10 +498,10 @@ packages:
dependency: "direct main"
description:
name: file_picker
sha256: "3d57312a53746ed4eb8c843dc50372454bbda37dd0c01a4d40fedc83e2ce4921"
sha256: ab13ae8ef5580a411c458d6207b6774a6c237d77ac37011b13994879f68a8810
url: "https://pub.dev"
source: hosted
version: "8.3.5"
version: "8.3.7"
file_saver:
dependency: "direct main"
description:
@@ -538,10 +538,10 @@ packages:
dependency: transitive
description:
name: file_selector_windows
sha256: "8f5d2f6590d51ecd9179ba39c64f722edc15226cc93dcc8698466ad36a4a85a4"
sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b"
url: "https://pub.dev"
source: hosted
version: "0.9.3+3"
version: "0.9.3+4"
firebase_analytics:
dependency: "direct main"
description:
@@ -1043,7 +1043,7 @@ packages:
source: hosted
version: "1.1.2"
image_picker_android:
dependency: transitive
dependency: "direct main"
description:
name: image_picker_android
sha256: b62d34a506e12bb965e824b6db4fbf709ee4589cf5d3e99b45ab2287b008ee0c
@@ -1158,18 +1158,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
url: "https://pub.dev"
source: hosted
version: "10.0.7"
version: "10.0.8"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
url: "https://pub.dev"
source: hosted
version: "3.0.8"
version: "3.0.9"
leak_tracker_testing:
dependency: transitive
description:
@@ -1238,10 +1238,10 @@ packages:
dependency: transitive
description:
name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
version: "0.12.17"
material_color_utilities:
dependency: transitive
description:
@@ -1342,10 +1342,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
url: "https://pub.dev"
source: hosted
version: "1.15.0"
version: "1.16.0"
mime:
dependency: "direct main"
description:
@@ -1414,10 +1414,10 @@ packages:
dependency: "direct main"
description:
name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
version: "1.9.1"
path_parsing:
dependency: transitive
description:
@@ -1534,10 +1534,10 @@ packages:
dependency: transitive
description:
name: petitparser
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646"
url: "https://pub.dev"
source: hosted
version: "6.0.2"
version: "6.1.0"
photo_view:
dependency: "direct main"
description:
@@ -1558,10 +1558,10 @@ packages:
dependency: transitive
description:
name: platform_detect
sha256: a62f99417fc4fa2d099ce0ccdbb1bd3977920f2a64292c326271f049d4bc3a4f
sha256: "7394dc1d884e652785a37c3ff25c54e503c6d9fa2f35b55d5efc0a133dec122c"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.5"
plugin_platform_interface:
dependency: transitive
description:
@@ -1883,10 +1883,10 @@ packages:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
version: "1.10.1"
sprintf:
dependency: transitive
description:
@@ -1899,34 +1899,34 @@ packages:
dependency: transitive
description:
name: sqflite
sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03
url: "https://pub.dev"
source: hosted
version: "2.4.1"
version: "2.4.2"
sqflite_android:
dependency: transitive
description:
name: sqflite_android
sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
sha256: "2b3070c5fa881839f8b402ee4a39c1b4d561704d4ebbbcfb808a119bc2a1701b"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.1"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
sha256: "84731e8bfd8303a3389903e01fb2141b6e59b5973cacbb0929021df08dddbe8b"
url: "https://pub.dev"
source: hosted
version: "2.5.4+6"
version: "2.5.5"
sqflite_darwin:
dependency: transitive
description:
name: sqflite_darwin
sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c"
sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3"
url: "https://pub.dev"
source: hosted
version: "2.4.1+1"
version: "2.4.2"
sqflite_platform_interface:
dependency: transitive
description:
@@ -1939,18 +1939,18 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
source: hosted
version: "1.12.0"
version: "1.12.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.4"
stream_transform:
dependency: transitive
description:
@@ -1963,10 +1963,10 @@ packages:
dependency: transitive
description:
name: string_scanner
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.4.1"
styled_widget:
dependency: "direct main"
description:
@@ -1987,26 +1987,26 @@ packages:
dependency: "direct main"
description:
name: synchronized
sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
sha256: "0669c70faae6270521ee4f05bffd2919892d42d1276e6c495be80174b6bc0ef6"
url: "https://pub.dev"
source: hosted
version: "3.3.0+3"
version: "3.3.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
version: "1.2.2"
test_api:
dependency: transitive
description:
name: test_api
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
url: "https://pub.dev"
source: hosted
version: "0.7.3"
version: "0.7.4"
timing:
dependency: transitive
description:
@@ -2195,10 +2195,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
url: "https://pub.dev"
source: hosted
version: "14.3.0"
version: "14.3.1"
volume_controller:
dependency: transitive
description:
@@ -2312,5 +2312,5 @@ packages:
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.6.0 <4.0.0"
dart: ">=3.7.0 <4.0.0"
flutter: ">=3.27.0"

View File

@@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 2.3.2+67
version: 2.3.2+69
environment:
sdk: ^3.5.4
@@ -120,6 +120,7 @@ dependencies:
xml: ^6.5.0
tray_manager: ^0.3.2
hotkey_manager: ^0.2.3
image_picker_android: ^0.8.12+20
dev_dependencies:
flutter_test: