D1APP-31 basic ui + audio recording support

This commit is contained in:
MohammadTaha Basiri 2022-01-01 14:12:44 +03:30
parent 551061111e
commit ba83575aaf
16 changed files with 325 additions and 40 deletions

View File

@ -26,7 +26,8 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android { android {
compileSdkVersion 30 compileSdkVersion 31
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8

View File

@ -1,5 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.didvan.didvanapp"> package="com.didvan.didvanapp">
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<application <application
android:label="Didvan" android:label="Didvan"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">

View File

@ -0,0 +1,135 @@
import 'dart:developer';
import 'package:just_audio/just_audio.dart';
import 'package:path_provider/path_provider.dart';
import 'package:record/record.dart';
import 'package:universal_html/js.dart' as js;
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/models/view/app_bar_data.dart';
import 'package:didvan/widgets/didvan/scaffold.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_vibrate/flutter_vibrate.dart';
class Chat extends StatelessWidget {
const Chat({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Material(
child: Stack(
children: [
Positioned(
top: 0,
bottom: 56,
left: 0,
right: 0,
child: DidvanScaffold(
appBarData: AppBarData(
hasBack: true,
subtitle: 'ارتباط با سردبیر',
title: 'رادار اقتصادی',
),
slivers: const [],
),
),
Positioned(
bottom: 0,
right: 0,
left: 0,
child: Container(
height: 56,
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: Theme.of(context).colorScheme.cardBorder,
),
),
color: Theme.of(context).colorScheme.surface,
),
child: Row(
children: [
const _VoiceRecorderButton(),
Expanded(
child: TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'بنویسید یا پیام صوتی بگذارید...',
hintStyle: Theme.of(context)
.textTheme
.caption!
.copyWith(
color: Theme.of(context).colorScheme.disabledText,
),
),
onChanged: (value) {},
),
),
],
),
),
),
],
),
);
}
}
class _VoiceRecorderButton extends StatefulWidget {
const _VoiceRecorderButton({Key? key}) : super(key: key);
@override
_VoiceRecorderButtonState createState() => _VoiceRecorderButtonState();
}
class _VoiceRecorderButtonState extends State<_VoiceRecorderButton> {
final _recorder = Record();
final _player = AudioPlayer();
@override
void initState() {
_recorder.hasPermission();
super.initState();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onLongPressStart: (details) async {
if (!kIsWeb) {
Vibrate.feedback(FeedbackType.medium);
}
await _recorder.start();
},
onLongPressEnd: (details) async {
final path = await _recorder.stop();
if (kIsWeb) {
await _player.setUrl(path!);
} else {
await _player.setFilePath(path!);
}
await _player.play();
if (kIsWeb) {
js.context.callMethod('playAudio', ['/dash.mp3']);
}
},
child: Container(
color: Colors.transparent,
height: double.infinity,
width: 52,
child: Icon(
DidvanIcons.mic_solid,
color: Theme.of(context).colorScheme.focusedBorder,
),
),
);
}
@override
void dispose() {
_recorder.dispose();
_player.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,3 @@
import 'package:didvan/providers/core_provider.dart';
class ChatState extends CoreProvier {}

View File

@ -133,7 +133,8 @@ class Settings extends StatelessWidget {
okText: 'تایید', okText: 'تایید',
cancelText: 'بازگشت', cancelText: 'بازگشت',
accentColor: Theme.of(context).colorScheme.primary, accentColor: Theme.of(context).colorScheme.primary,
okCancelStyle: Theme.of(context).textTheme.bodyText2!, okStyle: Theme.of(context).textTheme.bodyText2!,
cancelStyle: Theme.of(context).textTheme.bodyText2!,
unselectedColor: Theme.of(context).colorScheme.text, unselectedColor: Theme.of(context).colorScheme.text,
blurredBackground: true, blurredBackground: true,
hourLabel: 'ساعت', hourLabel: 'ساعت',

View File

@ -7,12 +7,12 @@ class SettingsState extends CoreProvier {
getSettingsFromStorage(); getSettingsFromStorage();
} }
List<String> _notificationTimeRange = []; List _notificationTimeRange = [];
String _fontFamily = 'Dana-FA'; String _fontFamily = 'Dana-FA';
double _fontSizeScale = 1; double _fontSizeScale = 1;
String _brightness = 'light'; String _brightness = 'light';
set notificationTimeRange(List<String> value) { set notificationTimeRange(List value) {
_notificationTimeRange = value; _notificationTimeRange = value;
StorageService.setValue( StorageService.setValue(
key: 'notificationTimeRange', key: 'notificationTimeRange',
@ -21,7 +21,7 @@ class SettingsState extends CoreProvier {
); );
} }
List<String> get notificationTimeRange => _notificationTimeRange; List get notificationTimeRange => _notificationTimeRange;
set fontFamily(String value) { set fontFamily(String value) {
_fontFamily = value; _fontFamily = value;

View File

@ -28,7 +28,12 @@ class MenuItem extends StatelessWidget {
color: Colors.transparent, color: Colors.transparent,
child: Row( child: Row(
children: [ children: [
if (icon != null) Icon(icon, size: 18, color: color), if (icon != null)
Icon(
icon,
size: 18,
color: color ?? Theme.of(context).colorScheme.title,
),
if (icon != null) const SizedBox(width: 4), if (icon != null) const SizedBox(width: 4),
DidvanText( DidvanText(
title, title,

View File

@ -1,5 +1,7 @@
import 'package:didvan/pages/authentication/authentication.dart'; import 'package:didvan/pages/authentication/authentication.dart';
import 'package:didvan/pages/authentication/authentication_state.dart'; import 'package:didvan/pages/authentication/authentication_state.dart';
import 'package:didvan/pages/home/chat/chat.dart';
import 'package:didvan/pages/home/chat/chat_state.dart';
import 'package:didvan/pages/home/home.dart'; import 'package:didvan/pages/home/home.dart';
import 'package:didvan/pages/home/home_state.dart'; import 'package:didvan/pages/home/home_state.dart';
import 'package:didvan/pages/home/news/news_details/news_details.dart'; import 'package:didvan/pages/home/news/news_details/news_details.dart';
@ -73,7 +75,13 @@ class RouteGenerator {
child: const ChatList(), child: const ChatList(),
), ),
); );
case Routes.chat:
return _createRoute(
ChangeNotifierProvider<ChatState>(
create: (context) => ChatState(),
child: const Chat(),
),
);
default: default:
return _errorRoute(); return _errorRoute();
} }

View File

@ -8,4 +8,5 @@ class Routes {
static const String radarDetails = '/radar-details'; static const String radarDetails = '/radar-details';
static const String newsDetails = '/news-details'; static const String newsDetails = '/news-details';
static const String chatList = '/chat-list'; static const String chatList = '/chat-list';
static const String chat = '/chat';
} }

View File

@ -1,15 +1,22 @@
import 'dart:io';
import 'package:didvan/models/settings_data.dart'; import 'package:didvan/models/settings_data.dart';
import 'package:didvan/services/storage/storage.dart'; import 'package:didvan/services/storage/storage.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hive/hive.dart'; import 'package:hive_flutter/hive_flutter.dart';
import 'package:path_provider/path_provider.dart'; import 'package:permission_handler/permission_handler.dart';
class AppInitializer { class AppInitializer {
static Future<void> setupServices() async { static Future<void> setupServices() async {
final Directory appDir = await getApplicationDocumentsDirectory(); // late final Directory appDir;
Hive.init(appDir.path); // late final Directory appTempsDir;
// if (!kIsWeb) {
await Hive.initFlutter();
// appDir = await getApplicationDocumentsDirectory();
// appTempsDir = await getApplicationDocumentsDirectory();
// }
// Hive.init(appDir.path);
// StorageService.appDocsDir = appDir.path;
// StorageService.appTempsDir = appTempsDir.path;
} }
static Future<ThemeMode> initilizeSettings() async { static Future<ThemeMode> initilizeSettings() async {

View File

@ -1,6 +1,9 @@
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
class StorageService { class StorageService {
static late final String appDocsDir;
static late final String appTempsDir;
static Future<void> setValue({ static Future<void> setValue({
required String key, required String key,
required dynamic value, required dynamic value,

View File

@ -9,9 +9,8 @@ class DidvanAppBar extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final MediaQueryData d = MediaQuery.of(context);
return Padding( return Padding(
padding: EdgeInsets.only(top: d.padding.top, right: 4, left: 20), padding: const EdgeInsets.only(right: 4, left: 20),
child: Row( child: Row(
children: [ children: [
IconButton( IconButton(
@ -34,7 +33,7 @@ class DidvanAppBar extends StatelessWidget {
), ),
if (appBarData.subtitle != null) if (appBarData.subtitle != null)
DidvanText( DidvanText(
appBarData.title!, appBarData.subtitle!,
style: Theme.of(context).textTheme.overline, style: Theme.of(context).textTheme.overline,
color: Theme.of(context).colorScheme.caption, color: Theme.of(context).colorScheme.caption,
), ),

View File

@ -1,3 +1,4 @@
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/widgets/didvan/text.dart'; import 'package:didvan/widgets/didvan/text.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -24,6 +25,7 @@ class DidvanBadge extends StatelessWidget {
text, text,
isEnglishFont: true, isEnglishFont: true,
style: Theme.of(context).textTheme.overline, style: Theme.of(context).textTheme.overline,
color: Theme.of(context).colorScheme.white,
), ),
), ),
); );

View File

@ -15,10 +15,14 @@ class DidvanScaffold extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final double statusBarHeight = MediaQuery.of(context).padding.top;
return Scaffold( return Scaffold(
body: CustomScrollView( body: Padding(
padding: EdgeInsets.only(top: statusBarHeight),
child: CustomScrollView(
slivers: [ slivers: [
SliverAppBar( SliverAppBar(
toolbarHeight: kToolbarHeight,
backgroundColor: Theme.of(context).backgroundColor, backgroundColor: Theme.of(context).backgroundColor,
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
pinned: true, pinned: true,
@ -39,6 +43,7 @@ class DidvanScaffold extends StatelessWidget {
), ),
], ],
), ),
),
); );
} }
} }

View File

@ -8,6 +8,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.8.2" version: "2.8.2"
audio_session:
dependency: transitive
description:
name: audio_session
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.6+1"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -85,6 +92,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.1" version: "3.0.1"
csslib:
dependency: transitive
description:
name: csslib
url: "https://pub.dartlang.org"
source: hosted
version: "0.17.1"
cupertino_icons: cupertino_icons:
dependency: "direct main" dependency: "direct main"
description: description:
@ -98,7 +112,7 @@ packages:
name: day_night_time_picker name: day_night_time_picker
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.3+1" version: "1.0.4+1"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -177,6 +191,13 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_vibrate:
dependency: "direct main"
description:
name: flutter_vibrate
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
flutter_web_plugins: flutter_web_plugins:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -196,6 +217,20 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.5" version: "2.0.5"
hive_flutter:
dependency: "direct main"
description:
name: hive_flutter
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
html:
dependency: transitive
description:
name: html
url: "https://pub.dartlang.org"
source: hosted
version: "0.15.0"
http: http:
dependency: transitive dependency: transitive
description: description:
@ -245,6 +280,27 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.6.3" version: "0.6.3"
just_audio:
dependency: "direct main"
description:
name: just_audio
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.18"
just_audio_platform_interface:
dependency: transitive
description:
name: just_audio_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.0"
just_audio_web:
dependency: transitive
description:
name: just_audio_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.2"
lints: lints:
dependency: transitive dependency: transitive
description: description:
@ -314,7 +370,7 @@ packages:
name: path_provider_android name: path_provider_android
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.9" version: "2.0.11"
path_provider_ios: path_provider_ios:
dependency: transitive dependency: transitive
description: description:
@ -357,6 +413,20 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.11.1" version: "1.11.1"
permission_handler:
dependency: "direct main"
description:
name: permission_handler
url: "https://pub.dartlang.org"
source: hosted
version: "8.3.0"
permission_handler_platform_interface:
dependency: transitive
description:
name: permission_handler_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.7.0"
petitparser: petitparser:
dependency: transitive dependency: transitive
description: description:
@ -398,7 +468,28 @@ packages:
name: provider name: provider
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "6.0.1" version: "6.0.2"
record:
dependency: "direct main"
description:
name: record
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.2"
record_platform_interface:
dependency: transitive
description:
name: record_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
record_web:
dependency: "direct main"
description:
name: record_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.1"
rive: rive:
dependency: "direct main" dependency: "direct main"
description: description:
@ -495,6 +586,20 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.3.0" version: "1.3.0"
universal_html:
dependency: "direct main"
description:
name: universal_html
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.8"
universal_io:
dependency: transitive
description:
name: universal_io
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
uuid: uuid:
dependency: transitive dependency: transitive
description: description:
@ -515,7 +620,7 @@ packages:
name: win32 name: win32
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.3.2" version: "2.3.3"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:

View File

@ -48,6 +48,14 @@ dependencies:
cached_network_image: ^3.2.0 cached_network_image: ^3.2.0
skeleton_text: ^3.0.0 skeleton_text: ^3.0.0
carousel_slider: ^4.0.0 carousel_slider: ^4.0.0
flutter_vibrate: ^1.3.0
hive_flutter: ^1.1.0
# flutter_sound: ^8.4.2
permission_handler: ^8.3.0
universal_html: ^2.0.8
record: ^3.0.2
just_audio: ^0.9.18
record_web: ^0.2.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: