Merge branch 'dev' into 'test'
Dev See merge request Didvan/didvan-app!4
This commit is contained in:
commit
bc443339a6
|
|
@ -65,5 +65,6 @@ flutter {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation platform('com.google.firebase:firebase-bom:29.1.0')
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"project_info": {
|
||||
"project_number": "935017686266",
|
||||
"project_id": "didvan-9b7da",
|
||||
"storage_bucket": "didvan-9b7da.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:935017686266:android:f9cbc9aba8e3d65ed2d543",
|
||||
"android_client_info": {
|
||||
"package_name": "com.didvan.didvanapp"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "935017686266-lebnol7rb05oi9h0mripb41c892d2gij.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyBp-UHjWeM0H0UHtX5yguFKG-riMzvvCzw"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "935017686266-lebnol7rb05oi9h0mripb41c892d2gij.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ buildscript {
|
|||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||
classpath 'com.google.gms:google-services:4.3.10'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Uncomment this line to define a global platform for your project
|
||||
platform :ios, '9.0'
|
||||
platform :ios, '10.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,41 @@
|
|||
PODS:
|
||||
- audio_session (0.0.1):
|
||||
- Flutter
|
||||
- Firebase/CoreOnly (8.11.0):
|
||||
- FirebaseCore (= 8.11.0)
|
||||
- Firebase/Messaging (8.11.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseMessaging (~> 8.11.0)
|
||||
- firebase_core (1.13.1):
|
||||
- Firebase/CoreOnly (= 8.11.0)
|
||||
- Flutter
|
||||
- firebase_messaging (11.2.8):
|
||||
- Firebase/Messaging (= 8.11.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- FirebaseCore (8.11.0):
|
||||
- FirebaseCoreDiagnostics (~> 8.0)
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- GoogleUtilities/Logger (~> 7.7)
|
||||
- FirebaseCoreDiagnostics (8.12.0):
|
||||
- GoogleDataTransport (~> 9.1)
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- GoogleUtilities/Logger (~> 7.7)
|
||||
- nanopb (~> 2.30908.0)
|
||||
- FirebaseInstallations (8.12.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- GoogleUtilities/UserDefaults (~> 7.7)
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- FirebaseMessaging (8.11.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseInstallations (~> 8.0)
|
||||
- GoogleDataTransport (~> 9.1)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.7)
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- GoogleUtilities/Reachability (~> 7.7)
|
||||
- GoogleUtilities/UserDefaults (~> 7.7)
|
||||
- nanopb (~> 2.30908.0)
|
||||
- Flutter (1.0.0)
|
||||
- flutter_secure_storage (3.3.1):
|
||||
- Flutter
|
||||
|
|
@ -9,6 +44,27 @@ PODS:
|
|||
- FMDB (2.7.5):
|
||||
- FMDB/standard (= 2.7.5)
|
||||
- FMDB/standard (2.7.5)
|
||||
- GoogleDataTransport (9.1.2):
|
||||
- GoogleUtilities/Environment (~> 7.2)
|
||||
- nanopb (~> 2.30908.0)
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- GoogleUtilities/AppDelegateSwizzler (7.7.0):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Environment (7.7.0):
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- GoogleUtilities/Logger (7.7.0):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Network (7.7.0):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (7.7.0)"
|
||||
- GoogleUtilities/Reachability (7.7.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/UserDefaults (7.7.0):
|
||||
- GoogleUtilities/Logger
|
||||
- image_cropper (0.0.4):
|
||||
- Flutter
|
||||
- TOCropViewController (~> 2.6.1)
|
||||
|
|
@ -16,8 +72,14 @@ PODS:
|
|||
- Flutter
|
||||
- just_audio (0.0.1):
|
||||
- Flutter
|
||||
- nanopb (2.30908.0):
|
||||
- nanopb/decode (= 2.30908.0)
|
||||
- nanopb/encode (= 2.30908.0)
|
||||
- nanopb/decode (2.30908.0)
|
||||
- nanopb/encode (2.30908.0)
|
||||
- path_provider_ios (0.0.1):
|
||||
- Flutter
|
||||
- PromisesObjC (2.0.0)
|
||||
- record (0.0.1):
|
||||
- Flutter
|
||||
- sqflite (0.0.2):
|
||||
|
|
@ -29,6 +91,8 @@ PODS:
|
|||
|
||||
DEPENDENCIES:
|
||||
- audio_session (from `.symlinks/plugins/audio_session/ios`)
|
||||
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
||||
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
||||
- flutter_vibrate (from `.symlinks/plugins/flutter_vibrate/ios`)
|
||||
|
|
@ -42,12 +106,25 @@ DEPENDENCIES:
|
|||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- Firebase
|
||||
- FirebaseCore
|
||||
- FirebaseCoreDiagnostics
|
||||
- FirebaseInstallations
|
||||
- FirebaseMessaging
|
||||
- FMDB
|
||||
- GoogleDataTransport
|
||||
- GoogleUtilities
|
||||
- nanopb
|
||||
- PromisesObjC
|
||||
- TOCropViewController
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
audio_session:
|
||||
:path: ".symlinks/plugins/audio_session/ios"
|
||||
firebase_core:
|
||||
:path: ".symlinks/plugins/firebase_core/ios"
|
||||
firebase_messaging:
|
||||
:path: ".symlinks/plugins/firebase_messaging/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_secure_storage:
|
||||
|
|
@ -71,19 +148,30 @@ EXTERNAL SOURCES:
|
|||
|
||||
SPEC CHECKSUMS:
|
||||
audio_session: 4f3e461722055d21515cf3261b64c973c062f345
|
||||
Firebase: 44dd9724c84df18b486639e874f31436eaa9a20c
|
||||
firebase_core: 08f6a85f62060111de5e98d6a214810d11365de9
|
||||
firebase_messaging: 36238f3d0b933af8c919aef608408aae06ba22e8
|
||||
FirebaseCore: 2f4f85b453cc8fea4bb2b37e370007d2bcafe3f0
|
||||
FirebaseCoreDiagnostics: 3b40dfadef5b90433a60ae01f01e90fe87aa76aa
|
||||
FirebaseInstallations: 25764cf322e77f99449395870a65b2bef88e1545
|
||||
FirebaseMessaging: 02e248e8997f71fa8cc9d78e9d49ec1a701ba14a
|
||||
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
|
||||
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
|
||||
flutter_vibrate: 9f4c2ab57008965f78969472367c329dd77eb801
|
||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
||||
GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940
|
||||
GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1
|
||||
image_cropper: 60c2789d1f1a78c873235d4319ca0c34a69f2d98
|
||||
image_picker: 9aa50e1d8cdacdbed739e925b7eea16d014367e6
|
||||
just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa
|
||||
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
|
||||
path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5
|
||||
PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58
|
||||
record: 7ee2393532f8553bbb09fa19e95478323b7c0a99
|
||||
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
|
||||
TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863
|
||||
url_launcher_ios: 02f1989d4e14e998335b02b67a7590fa34f971af
|
||||
|
||||
PODFILE CHECKSUM: a75497545d4391e2d394c3668e20cfb1c2bbd4aa
|
||||
PODFILE CHECKSUM: fe0e1ee7f3d1f7d00b11b474b62dd62134535aea
|
||||
|
||||
COCOAPODS: 1.11.2
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
D194CE3E27D4A4740049AFC7 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = D194CE3D27D4A4740049AFC7 /* GoogleService-Info.plist */; };
|
||||
E870A5F479A60D6704DD5DF2 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75DBECA488F412614712FB74 /* Pods_Runner.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
|
|
@ -47,6 +48,7 @@
|
|||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
98ACB01D5FA5A78DB2686183 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
C97DED20C4A171F16FB949CD /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
D194CE3D27D4A4740049AFC7 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
|
@ -112,6 +114,7 @@
|
|||
97C146F01CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D194CE3D27D4A4740049AFC7 /* GoogleService-Info.plist */,
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||
|
|
@ -189,6 +192,7 @@
|
|||
files = (
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||
D194CE3E27D4A4740049AFC7 /* GoogleService-Info.plist in Resources */,
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,30 @@
|
|||
import UIKit
|
||||
import Flutter
|
||||
import Firebase
|
||||
|
||||
|
||||
@UIApplicationMain
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
@objc class AppDelegate: FlutterAppDelegate, MessagingDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
FirebaseApp.configure()
|
||||
Messaging.messaging().delegate = self
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
if #available(iOS 10.0, *) {
|
||||
// For iOS 10 display notification (sent via APNS)
|
||||
UNUserNotificationCenter.current().delegate = self
|
||||
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
|
||||
UNUserNotificationCenter.current().requestAuthorization(
|
||||
options: authOptions,
|
||||
completionHandler: {_, _ in })
|
||||
} else {
|
||||
let settings: UIUserNotificationSettings =
|
||||
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
|
||||
application.registerUserNotificationSettings(settings)
|
||||
}
|
||||
application.registerForRemoteNotifications()
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CLIENT_ID</key>
|
||||
<string>935017686266-54hu01v9cc5pqpgofo1gk2n3hegj4r2m.apps.googleusercontent.com</string>
|
||||
<key>REVERSED_CLIENT_ID</key>
|
||||
<string>com.googleusercontent.apps.935017686266-54hu01v9cc5pqpgofo1gk2n3hegj4r2m</string>
|
||||
<key>API_KEY</key>
|
||||
<string>AIzaSyCMa-zg_uVhOfTnea5Klz6aPZlgHwVGj7U</string>
|
||||
<key>GCM_SENDER_ID</key>
|
||||
<string>935017686266</string>
|
||||
<key>PLIST_VERSION</key>
|
||||
<string>1</string>
|
||||
<key>BUNDLE_ID</key>
|
||||
<string>com.didvan.didvanapp</string>
|
||||
<key>PROJECT_ID</key>
|
||||
<string>didvan-9b7da</string>
|
||||
<key>STORAGE_BUCKET</key>
|
||||
<string>didvan-9b7da.appspot.com</string>
|
||||
<key>IS_ADS_ENABLED</key>
|
||||
<false></false>
|
||||
<key>IS_ANALYTICS_ENABLED</key>
|
||||
<false></false>
|
||||
<key>IS_APPINVITE_ENABLED</key>
|
||||
<true></true>
|
||||
<key>IS_GCM_ENABLED</key>
|
||||
<true></true>
|
||||
<key>IS_SIGNIN_ENABLED</key>
|
||||
<true></true>
|
||||
<key>GOOGLE_APP_ID</key>
|
||||
<string>1:935017686266:ios:de47638bd662463fd2d543</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -26,6 +26,8 @@
|
|||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>FirebaseAppDelegateProxyEnabled</key>
|
||||
<false/>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>We need to access to the microphone to record audio file</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ class Content {
|
|||
final String? audio;
|
||||
final String? video;
|
||||
final String? image;
|
||||
final String? largeImage;
|
||||
final String? caption;
|
||||
|
||||
const Content({
|
||||
required this.order,
|
||||
|
|
@ -11,6 +13,8 @@ class Content {
|
|||
required this.audio,
|
||||
required this.video,
|
||||
required this.image,
|
||||
required this.largeImage,
|
||||
required this.caption,
|
||||
});
|
||||
|
||||
factory Content.fromJson(Map<String, dynamic> json) => Content(
|
||||
|
|
@ -19,6 +23,8 @@ class Content {
|
|||
audio: json['audio'],
|
||||
video: json['video'],
|
||||
image: json['image'],
|
||||
largeImage: json['largeImage'],
|
||||
caption: json['caption'],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
|
|
@ -27,5 +33,7 @@ class Content {
|
|||
'audio': audio,
|
||||
'video': video,
|
||||
'image': image,
|
||||
'largeImage': largeImage,
|
||||
'caption': caption,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class ServerDataProvider {
|
|||
directTypes.add(MapEntry(types[i]['id'], types[i]['label']));
|
||||
}
|
||||
} else {
|
||||
throw 'Fetchin direct types failed!';
|
||||
throw 'Fetching direct types failed!';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,10 @@ import 'package:didvan/views/home/settings/direct_list/direct_list_state.dart';
|
|||
import 'package:didvan/views/home/settings/general_settings/settings.dart';
|
||||
import 'package:didvan/views/home/settings/general_settings/settings_state.dart';
|
||||
import 'package:didvan/views/home/settings/profile/profile.dart';
|
||||
import 'package:didvan/views/home/studio/studio_state.dart';
|
||||
import 'package:didvan/views/splash/splash.dart';
|
||||
import 'package:didvan/routes/routes.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
|
|
@ -57,6 +59,9 @@ class RouteGenerator {
|
|||
ChangeNotifierProvider<NewsState>(
|
||||
create: (context) => NewsState(),
|
||||
),
|
||||
ChangeNotifierProvider<StudioState>(
|
||||
create: (context) => StudioState(),
|
||||
),
|
||||
],
|
||||
child: const Home(),
|
||||
),
|
||||
|
|
@ -161,13 +166,20 @@ class RouteGenerator {
|
|||
|
||||
static Route _createRoute(page) {
|
||||
return MaterialPageRoute(
|
||||
builder: (context) => Container(
|
||||
builder: (context) {
|
||||
final shortestSide = MediaQuery.of(context).size.shortestSide;
|
||||
final bool useMobileLayout = shortestSide < 600;
|
||||
if (kIsWeb && !useMobileLayout) {
|
||||
return Center(child: AspectRatio(aspectRatio: 9 / 16, child: page));
|
||||
}
|
||||
return Container(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: SafeArea(
|
||||
child: page,
|
||||
top: false,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import 'package:didvan/services/media/media.dart';
|
||||
import 'package:didvan/services/storage/storage.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
|
@ -10,6 +12,7 @@ class AppInitializer {
|
|||
StorageService.appDocsDir =
|
||||
(await getApplicationDocumentsDirectory()).path;
|
||||
StorageService.appTempsDir = (await getTemporaryDirectory()).path;
|
||||
await _initializeFirebase();
|
||||
MediaService.init();
|
||||
}
|
||||
}
|
||||
|
|
@ -42,4 +45,29 @@ class AppInitializer {
|
|||
return ThemeMode.light;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> _initializeFirebase() async {
|
||||
try {
|
||||
await Firebase.initializeApp(
|
||||
options: const FirebaseOptions(
|
||||
apiKey: 'AIzaSyBp-UHjWeM0H0UHtX5yguFKG-riMzvvCzw',
|
||||
appId: '1:935017686266:android:f9cbc9aba8e3d65ed2d543',
|
||||
messagingSenderId: '935017686266',
|
||||
projectId: 'didvan-9b7da',
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
Firebase.app();
|
||||
}
|
||||
final FirebaseMessaging fcm = FirebaseMessaging.instance;
|
||||
await fcm.requestPermission(
|
||||
alert: true,
|
||||
announcement: false,
|
||||
badge: true,
|
||||
carPlay: false,
|
||||
criticalAlert: false,
|
||||
provisional: false,
|
||||
sound: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import 'package:just_audio/just_audio.dart';
|
|||
class MediaService {
|
||||
static final AudioPlayer audioPlayer = AudioPlayer();
|
||||
static String? audioPlayerTag;
|
||||
static String? audioPlayerTitle;
|
||||
static String? audioPlayerCover;
|
||||
|
||||
static void init() {
|
||||
audioPlayer.positionStream.listen((event) {
|
||||
|
|
@ -54,6 +56,11 @@ class MediaService {
|
|||
}
|
||||
}
|
||||
|
||||
static Future<void> resetAudioPlayer() async {
|
||||
audioPlayerTag = null;
|
||||
MediaService.audioPlayer.stop();
|
||||
}
|
||||
|
||||
static Future<XFile?> pickImage({required ImageSource source}) async {
|
||||
final imagePicker = ImagePicker();
|
||||
final XFile? pickedFile = await imagePicker.pickImage(source: source);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class RequestHelper {
|
|||
_urlConcatGenerator([
|
||||
MapEntry('limit', limit?.toString() ?? '3'),
|
||||
MapEntry('type', type),
|
||||
MapEntry('id', itemId.toString()),
|
||||
MapEntry('id', itemId?.toString() ?? '1'),
|
||||
MapEntry('tags', _urlListConcatGenerator(ids))
|
||||
]);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import 'package:didvan/views/widgets/didvan/text_field.dart';
|
|||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class UsernameInput extends StatefulWidget {
|
||||
const UsernameInput({
|
||||
|
|
@ -70,7 +71,7 @@ class _UsernameInputState extends State<UsernameInput> {
|
|||
.textTheme
|
||||
.caption!
|
||||
.copyWith(color: Theme.of(context).colorScheme.primary),
|
||||
recognizer: TapGestureRecognizer()..onTap = () {},
|
||||
recognizer: TapGestureRecognizer()..onTap = _openTermsOfUse,
|
||||
),
|
||||
const TextSpan(text: 'و\n'),
|
||||
TextSpan(
|
||||
|
|
@ -79,7 +80,7 @@ class _UsernameInputState extends State<UsernameInput> {
|
|||
.textTheme
|
||||
.caption!
|
||||
.copyWith(color: Theme.of(context).colorScheme.primary),
|
||||
recognizer: TapGestureRecognizer()..onTap = () {},
|
||||
recognizer: TapGestureRecognizer()..onTap = _openTermsOfUse,
|
||||
),
|
||||
const TextSpan(text: 'را میپذیرم'),
|
||||
],
|
||||
|
|
@ -92,4 +93,8 @@ class _UsernameInputState extends State<UsernameInput> {
|
|||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _openTermsOfUse() {
|
||||
launch('https://didvan.app/termsOfUse.html');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:didvan/models/enums.dart';
|
||||
import 'package:didvan/models/view/app_bar_data.dart';
|
||||
import 'package:didvan/providers/server_data_provider.dart';
|
||||
import 'package:didvan/services/media/media.dart';
|
||||
import 'package:didvan/views/home/direct/direct_state.dart';
|
||||
import 'package:didvan/views/home/direct/widgets/message.dart';
|
||||
import 'package:didvan/views/home/direct/widgets/message_box.dart';
|
||||
|
|
@ -35,7 +36,12 @@ class _DirectState extends State<Direct> {
|
|||
Widget build(BuildContext context) {
|
||||
final state = context.watch<DirectState>();
|
||||
final d = MediaQuery.of(context);
|
||||
return Material(
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
MediaService.resetAudioPlayer();
|
||||
return true;
|
||||
},
|
||||
child: Material(
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
|
|
@ -89,6 +95,7 @@ class _DirectState extends State<Direct> {
|
|||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:didvan/models/enums.dart';
|
||||
|
|
@ -31,7 +32,7 @@ class DirectState extends CoreProvier {
|
|||
final messageDatas = service.result['messages'];
|
||||
for (var i = 0; i < messageDatas.length; i++) {
|
||||
messages.add(MessageData.fromJson(messageDatas[i]));
|
||||
_addToDailyGrouped();
|
||||
_addToDailyGrouped(messages.last);
|
||||
}
|
||||
appState = AppState.idle;
|
||||
return;
|
||||
|
|
@ -75,8 +76,8 @@ class DirectState extends CoreProvier {
|
|||
}
|
||||
}
|
||||
|
||||
void _addToDailyGrouped() {
|
||||
final createdAt = messages.last.createdAt.split('T').first;
|
||||
void _addToDailyGrouped(MessageData message) {
|
||||
String createdAt = message.createdAt.replaceAll('T', ' ').split(' ').first;
|
||||
if (!dailyMessages.containsKey(createdAt)) {
|
||||
dailyMessages.addAll({
|
||||
createdAt: [messages.last.id]
|
||||
|
|
@ -88,7 +89,6 @@ class DirectState extends CoreProvier {
|
|||
|
||||
Future<void> sendMessage() async {
|
||||
if ((text == null || text!.isEmpty) && recordedFile == null) return;
|
||||
replyRadar = null;
|
||||
messages.insert(
|
||||
0,
|
||||
MessageData(
|
||||
|
|
@ -104,7 +104,7 @@ class DirectState extends CoreProvier {
|
|||
audioDuration: audioDuration,
|
||||
),
|
||||
);
|
||||
_addToDailyGrouped();
|
||||
_addToDailyGrouped(messages.first);
|
||||
final body = {};
|
||||
if (text != null) {
|
||||
body.addAll({'text': text});
|
||||
|
|
@ -115,6 +115,7 @@ class DirectState extends CoreProvier {
|
|||
final uploadFile = recordedFile;
|
||||
text = null;
|
||||
recordedFile = null;
|
||||
replyRadar = null;
|
||||
notifyListeners();
|
||||
final service =
|
||||
RequestService(RequestHelper.sendDirectMessage(typeId), body: body);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ class Message extends StatelessWidget {
|
|||
_MessageContainer(
|
||||
writedByAdmin: message.writedByAdmin,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (message.text != null) DidvanText(message.text!),
|
||||
if (message.audio != null || message.audioFile != null)
|
||||
|
|
|
|||
|
|
@ -28,12 +28,19 @@ class _HashtagState extends State<Hashtag> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DidvanScaffold(
|
||||
appBarData: AppBarData(title: widget.tag.label, hasBack: true),
|
||||
appBarData: AppBarData(title: '#' + widget.tag.label, hasBack: true),
|
||||
slivers: [
|
||||
Consumer<HashtagState>(
|
||||
builder: (context, state, child) => SliverStateHandler<HashtagState>(
|
||||
itemPadding: const EdgeInsets.only(bottom: 8),
|
||||
state: state,
|
||||
placeholder: RadarOverview.placeholder,
|
||||
builder: (context, state, index) {
|
||||
index++;
|
||||
if (index % 15 == 0 && index / 15 >= state.page) {
|
||||
state.getTagItems(page: index ~/ 15 + 1);
|
||||
}
|
||||
index--;
|
||||
final item = state.items[index];
|
||||
final type = item.type;
|
||||
if (type == 'radar') {
|
||||
|
|
@ -51,7 +58,7 @@ class _HashtagState extends State<Hashtag> {
|
|||
return Container();
|
||||
},
|
||||
childCount: state.items.length,
|
||||
onRetry: () {},
|
||||
onRetry: () => state.getTagItems(page: 1),
|
||||
),
|
||||
)
|
||||
],
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ class HashtagState extends CoreProvier {
|
|||
}
|
||||
final service = RequestService(RequestHelper.tag(
|
||||
ids: [id],
|
||||
itemId: 1,
|
||||
type: 'radar',
|
||||
limit: 15,
|
||||
page: page,
|
||||
));
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ class _RadarState extends State<Radar> {
|
|||
CustomScrollView(
|
||||
physics: _isAnimating
|
||||
? const NeverScrollableScrollPhysics()
|
||||
: const ScrollPhysics(),
|
||||
: const ClampingScrollPhysics(),
|
||||
controller: _scrollController,
|
||||
slivers: [
|
||||
const SliverToBoxAdapter(child: LogoAppBar()),
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import 'package:didvan/models/requests/radar.dart';
|
|||
import 'package:didvan/providers/core_provider.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:didvan/services/network/request_helper.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class RadarDetailsState extends CoreProvier {
|
||||
final List<RadarDetailsData?> radars = [];
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import 'package:didvan/models/view/radar_category.dart';
|
|||
import 'package:didvan/views/home/radar/radar_state.dart';
|
||||
import 'package:didvan/views/widgets/animated_visibility.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
|
@ -18,6 +19,22 @@ class CategoryItem extends StatelessWidget {
|
|||
required this.category,
|
||||
}) : super(key: key);
|
||||
|
||||
double _width(context) {
|
||||
final Size ds = MediaQuery.of(context).size;
|
||||
if (kIsWeb) {
|
||||
if (!_useWebMobileLayout(context)) {
|
||||
return ds.height / 16 * 9 / 3;
|
||||
}
|
||||
}
|
||||
return ds.width / 3;
|
||||
}
|
||||
|
||||
bool _useWebMobileLayout(context) {
|
||||
final shortestSide = MediaQuery.of(context).size.shortestSide;
|
||||
final bool useMobileLayout = shortestSide < 600;
|
||||
return kIsWeb && useMobileLayout;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Size ds = MediaQuery.of(context).size;
|
||||
|
|
@ -34,7 +51,7 @@ class CategoryItem extends StatelessWidget {
|
|||
child: AnimatedContainer(
|
||||
duration: DesignConfig.mediumAnimationDuration,
|
||||
padding: isColapsed ? const EdgeInsets.all(4) : EdgeInsets.zero,
|
||||
width: isColapsed ? 100 : ds.width / 3,
|
||||
width: isColapsed ? 100 : _width(context),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: DesignConfig.lowBorderRadius,
|
||||
|
|
@ -48,8 +65,12 @@ class CategoryItem extends StatelessWidget {
|
|||
duration: DesignConfig.mediumAnimationDuration,
|
||||
isVisible: !isColapsed,
|
||||
child: Container(
|
||||
width: ds.width / 5,
|
||||
height: ds.width / 5,
|
||||
width: !_useWebMobileLayout(context)
|
||||
? _width(context) / 2
|
||||
: ds.width / 5,
|
||||
height: !_useWebMobileLayout(context)
|
||||
? _width(context) / 2
|
||||
: ds.width / 5,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
boxShadow: DesignConfig.defaultShadow,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class PodcastDetails extends StatelessWidget {
|
||||
const PodcastDetails({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(8)),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,17 @@
|
|||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/models/view/action_sheet_data.dart';
|
||||
import 'package:didvan/utils/action_sheet.dart';
|
||||
import 'package:didvan/views/home/studio/studio_state.dart';
|
||||
import 'package:didvan/views/home/studio/widgets/slider.dart';
|
||||
import 'package:didvan/views/home/studio/widgets/tab_bar.dart';
|
||||
import 'package:didvan/views/home/widgets/logo_app_bar.dart';
|
||||
import 'package:didvan/views/home/widgets/search_field.dart';
|
||||
import 'package:didvan/views/widgets/didvan/divider.dart';
|
||||
import 'package:didvan/views/widgets/didvan/icon_button.dart';
|
||||
import 'package:didvan/views/widgets/didvan/radial_button.dart';
|
||||
import 'package:didvan/views/widgets/item_title.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class Studio extends StatefulWidget {
|
||||
const Studio({Key? key}) : super(key: key);
|
||||
|
|
@ -51,7 +58,73 @@ class _StudioState extends State<Studio> {
|
|||
const SliverToBoxAdapter(
|
||||
child: StudioSlider(),
|
||||
),
|
||||
const SliverPadding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: DidvanDivider(
|
||||
verticalPadding: 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const ItemTitle(title: 'تازهترینها'),
|
||||
DidvanIconButton(
|
||||
gestureSize: 36,
|
||||
icon: DidvanIcons.sort_regular,
|
||||
onPressed: _showSortDialog,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _showSortDialog() {
|
||||
final state = context.read<StudioState>();
|
||||
ActionSheetUtils.showBottomSheet(
|
||||
data: ActionSheetData(
|
||||
content: StatefulBuilder(
|
||||
builder: (context, setState) => Column(
|
||||
children: [
|
||||
DidvanRadialButton(
|
||||
title: 'جدیدترینها',
|
||||
onSelected: () => setState(
|
||||
() => state.selectedSortTypeIndex = 0,
|
||||
),
|
||||
value: state.selectedSortTypeIndex == 0,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
DidvanRadialButton(
|
||||
title: 'پربازدیدترینها',
|
||||
onSelected: () => setState(
|
||||
() => state.selectedSortTypeIndex = 1,
|
||||
),
|
||||
value: state.selectedSortTypeIndex == 1,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
DidvanRadialButton(
|
||||
title: 'پربحثترینها',
|
||||
onSelected: () => setState(
|
||||
() => state.selectedSortTypeIndex = 2,
|
||||
),
|
||||
value: state.selectedSortTypeIndex == 2,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
title: 'مرتبسازی',
|
||||
titleIcon: DidvanIcons.sort_regular,
|
||||
hasDismissButton: false,
|
||||
confrimTitle: 'مرتب سازی',
|
||||
onConfirmed: () {},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import 'package:didvan/providers/core_provider.dart';
|
||||
|
||||
class StudioState extends CoreProvier {
|
||||
int selectedSortTypeIndex = 0;
|
||||
|
||||
bool videosSelected = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/views/home/studio/studio_state.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class StudioTabBar extends StatelessWidget {
|
||||
const StudioTabBar({
|
||||
|
|
@ -11,11 +13,16 @@ class StudioTabBar extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final state = context.watch<StudioState>();
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||
padding: const EdgeInsets.all(4),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Theme.of(context).colorScheme.border),
|
||||
border: Border.all(
|
||||
color: state.videosSelected
|
||||
? Theme.of(context).colorScheme.secondary
|
||||
: Theme.of(context).primaryColor,
|
||||
),
|
||||
borderRadius: DesignConfig.lowBorderRadius,
|
||||
),
|
||||
child: Row(
|
||||
|
|
@ -26,7 +33,7 @@ class StudioTabBar extends StatelessWidget {
|
|||
selectedColor: Theme.of(context).colorScheme.secondary,
|
||||
title: 'ویدئو',
|
||||
onTap: () {},
|
||||
isSelected: true,
|
||||
isSelected: state.videosSelected,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
|
|
@ -40,7 +47,7 @@ class StudioTabBar extends StatelessWidget {
|
|||
selectedColor: Theme.of(context).colorScheme.focusedBorder,
|
||||
title: 'پادکست',
|
||||
onTap: () {},
|
||||
isSelected: true,
|
||||
isSelected: !state.videosSelected,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
@ -64,7 +71,8 @@ class _StudioTypeButton extends StatelessWidget {
|
|||
required this.isSelected,
|
||||
}) : super(key: key);
|
||||
|
||||
Color? get _color => isSelected ? selectedColor : null;
|
||||
Color? _color(context) =>
|
||||
isSelected ? selectedColor : Theme.of(context).colorScheme.hint;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -77,20 +85,20 @@ class _StudioTypeButton extends StatelessWidget {
|
|||
Icon(
|
||||
icon,
|
||||
size: 32,
|
||||
color: _color,
|
||||
color: _color(context),
|
||||
),
|
||||
if (!isSelected) const SizedBox(height: 18),
|
||||
if (isSelected)
|
||||
Container(
|
||||
width: 88,
|
||||
height: 1,
|
||||
color: _color,
|
||||
color: _color(context),
|
||||
),
|
||||
if (isSelected)
|
||||
DidvanText(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.overline,
|
||||
color: _color,
|
||||
color: _color(context),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/services/media/media.dart';
|
||||
import 'package:didvan/views/widgets/didvan/icon_button.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:didvan/views/widgets/skeleton_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DidvanBNB extends StatelessWidget {
|
||||
|
|
@ -14,11 +17,46 @@ class DidvanBNB extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
return StreamBuilder<bool>(
|
||||
stream: MediaService.audioPlayer.playingStream,
|
||||
builder: (context, snapshot) {
|
||||
return Stack(
|
||||
children: [
|
||||
AnimatedContainer(
|
||||
duration: DesignConfig.lowAnimationDuration,
|
||||
height: snapshot.data == true ? 120 : 72,
|
||||
decoration: BoxDecoration(
|
||||
color: DesignConfig.isDark
|
||||
? Theme.of(context).colorScheme.focused
|
||||
: Theme.of(context).colorScheme.navigation,
|
||||
borderRadius: const BorderRadius.vertical(
|
||||
top: Radius.circular(16),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const DidvanIconButton(
|
||||
icon: DidvanIcons.close_regular,
|
||||
gestureSize: 24,
|
||||
onPressed: MediaService.resetAudioPlayer,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
if (MediaService.audioPlayerCover != null)
|
||||
SkeletonImage(imageUrl: MediaService.audioPlayerCover!),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
height: 72,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
|
||||
borderRadius:
|
||||
const BorderRadius.vertical(top: Radius.circular(16)),
|
||||
boxShadow: DesignConfig.defaultShadow,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
|
|
@ -61,7 +99,11 @@ class DidvanBNB extends StatelessWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,138 @@
|
|||
import 'package:didvan/models/overview_data.dart';
|
||||
import 'package:didvan/models/requests/news.dart';
|
||||
import 'package:didvan/routes/routes.dart';
|
||||
import 'package:didvan/utils/date_time.dart';
|
||||
import 'package:didvan/views/home/widgets/bookmark_button.dart';
|
||||
import 'package:didvan/views/widgets/didvan/card.dart';
|
||||
import 'package:didvan/views/widgets/didvan/divider.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
|
||||
import 'package:didvan/views/widgets/skeleton_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class PodcastOverview extends StatelessWidget {
|
||||
final OverviewData news;
|
||||
final NewsRequestArgs? newsRequestArgs;
|
||||
final void Function(int id, bool value) onMarkChanged;
|
||||
final bool hasUnmarkConfirmation;
|
||||
const PodcastOverview({
|
||||
Key? key,
|
||||
required this.news,
|
||||
required this.onMarkChanged,
|
||||
this.newsRequestArgs,
|
||||
this.hasUnmarkConfirmation = false,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DidvanCard(
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.newsDetails,
|
||||
arguments: {
|
||||
'onMarkChanged': onMarkChanged,
|
||||
'id': news.id,
|
||||
'args': newsRequestArgs,
|
||||
'hasUnmarkConfirmation': hasUnmarkConfirmation,
|
||||
},
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
SkeletonImage(
|
||||
imageUrl: news.image,
|
||||
width: 64,
|
||||
height: 64,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 64,
|
||||
child: DidvanText(
|
||||
news.title,
|
||||
style: Theme.of(context).textTheme.bodyText1,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
DidvanText(
|
||||
news.description,
|
||||
maxLines: 3,
|
||||
),
|
||||
const DidvanDivider(verticalPadding: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
DidvanText(
|
||||
news.reference!,
|
||||
style: Theme.of(context).textTheme.caption,
|
||||
),
|
||||
DidvanText(
|
||||
' - ' + DateTimeUtils.momentGenerator(news.createdAt),
|
||||
style: Theme.of(context).textTheme.caption,
|
||||
),
|
||||
],
|
||||
),
|
||||
BookmarkButton(
|
||||
value: news.marked,
|
||||
onMarkChanged: (value) => onMarkChanged(news.id, value),
|
||||
askForConfirmation: hasUnmarkConfirmation,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static Widget get placeholder => DidvanCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const ShimmerPlaceholder(height: 64, width: 64),
|
||||
const SizedBox(width: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: const [
|
||||
ShimmerPlaceholder(height: 18, width: 200),
|
||||
SizedBox(height: 8),
|
||||
ShimmerPlaceholder(height: 18, width: 100),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const ShimmerPlaceholder(
|
||||
height: 16,
|
||||
width: double.infinity,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const ShimmerPlaceholder(
|
||||
height: 16,
|
||||
width: double.infinity,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const ShimmerPlaceholder(
|
||||
height: 16,
|
||||
width: 100,
|
||||
),
|
||||
const DidvanDivider(verticalPadding: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: const [
|
||||
ShimmerPlaceholder(height: 12, width: 150),
|
||||
ShimmerPlaceholder(height: 24, width: 24),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ import 'package:didvan/views/home/widgets/tag_item.dart';
|
|||
import 'package:didvan/views/widgets/animated_visibility.dart';
|
||||
import 'package:didvan/views/widgets/didvan/card.dart';
|
||||
import 'package:didvan/views/widgets/didvan/divider.dart';
|
||||
import 'package:didvan/views/widgets/didvan/icon_button.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:didvan/views/widgets/ink_wrapper.dart';
|
||||
import 'package:didvan/views/widgets/item_title.dart';
|
||||
|
|
@ -191,14 +190,17 @@ class _DidvanPageViewState extends State<DidvanPageView> {
|
|||
margin: EdgeInsets.zero,
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
'span': Style(
|
||||
textAlign: TextAlign.center,
|
||||
fontSize: FontSize.small,
|
||||
alignment: Alignment.center,
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
if (content.caption != null) {
|
||||
return Center(
|
||||
child: DidvanText(
|
||||
content.caption,
|
||||
style: Theme.of(context).textTheme.caption,
|
||||
),
|
||||
);
|
||||
}
|
||||
if (content.image != null) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
|
|
@ -211,19 +213,15 @@ class _DidvanPageViewState extends State<DidvanPageView> {
|
|||
child: Center(
|
||||
child: SkeletonImage(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: 200,
|
||||
imageUrl: content.image,
|
||||
imageUrl: content.largeImage ?? content.image,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 16,
|
||||
child: DidvanIconButton(
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
icon: DidvanIcons.back_regular,
|
||||
onPressed: Navigator.of(context).pop,
|
||||
),
|
||||
const Positioned(
|
||||
right: 24,
|
||||
top: 24,
|
||||
child: _BackButton(),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -231,7 +229,7 @@ class _DidvanPageViewState extends State<DidvanPageView> {
|
|||
},
|
||||
child: SkeletonImage(
|
||||
imageUrl: content.image!,
|
||||
aspectRatio: 16 / 9,
|
||||
width: double.infinity,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -277,9 +275,8 @@ class _DidvanPageViewState extends State<DidvanPageView> {
|
|||
}
|
||||
|
||||
class _BackButton extends StatefulWidget {
|
||||
final ScrollController scrollController;
|
||||
const _BackButton({Key? key, required this.scrollController})
|
||||
: super(key: key);
|
||||
final ScrollController? scrollController;
|
||||
const _BackButton({Key? key, this.scrollController}) : super(key: key);
|
||||
|
||||
@override
|
||||
__BackButtonState createState() => __BackButtonState();
|
||||
|
|
@ -290,20 +287,26 @@ class __BackButtonState extends State<_BackButton> {
|
|||
|
||||
@override
|
||||
void didUpdateWidget(covariant _BackButton oldWidget) {
|
||||
if (widget.scrollController != null) {
|
||||
_isVisible = false;
|
||||
_handleScroll();
|
||||
}
|
||||
super.didUpdateWidget(oldWidget);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
if (widget.scrollController != null) {
|
||||
_handleScroll();
|
||||
} else {
|
||||
_isVisible = true;
|
||||
}
|
||||
super.initState();
|
||||
}
|
||||
|
||||
void _handleScroll() {
|
||||
widget.scrollController.addListener(() {
|
||||
final position = widget.scrollController.position.pixels;
|
||||
widget.scrollController!.addListener(() {
|
||||
final position = widget.scrollController!.position.pixels;
|
||||
final size = MediaQuery.of(context).size.height * 0.3;
|
||||
if (position > size && _isVisible == false) {
|
||||
setState(() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DidvanRadialButton extends StatelessWidget {
|
||||
final String title;
|
||||
final VoidCallback onSelected;
|
||||
final bool value;
|
||||
const DidvanRadialButton({
|
||||
Key? key,
|
||||
required this.title,
|
||||
required this.onSelected,
|
||||
required this.value,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: value ? null : onSelected,
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(4),
|
||||
height: 24,
|
||||
width: 24,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: value
|
||||
? Theme.of(context).colorScheme.secondary
|
||||
: Theme.of(context).colorScheme.text,
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: value
|
||||
? Theme.of(context).colorScheme.secondary
|
||||
: Colors.transparent,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
DidvanText(title),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,17 +8,17 @@ import 'package:cached_network_image_platform_interface/cached_network_image_pla
|
|||
|
||||
class SkeletonImage extends StatelessWidget {
|
||||
final String imageUrl;
|
||||
final double width;
|
||||
final double height;
|
||||
final double? width;
|
||||
final double? height;
|
||||
final BorderRadius? borderRadius;
|
||||
final double? aspectRatio;
|
||||
const SkeletonImage({
|
||||
Key? key,
|
||||
required this.imageUrl,
|
||||
this.width = 300,
|
||||
this.height = 140,
|
||||
this.borderRadius = DesignConfig.lowBorderRadius,
|
||||
this.aspectRatio,
|
||||
this.width,
|
||||
this.height,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
|
|
@ -30,15 +30,13 @@ class SkeletonImage extends StatelessWidget {
|
|||
width: width,
|
||||
height: height,
|
||||
imageUrl: RequestHelper.baseUrl + imageUrl,
|
||||
imageBuilder: (context, imageProvider) => Container(
|
||||
decoration: BoxDecoration(
|
||||
imageBuilder: (context, imageProvider) => ClipRRect(
|
||||
borderRadius: borderRadius ?? DesignConfig.lowBorderRadius,
|
||||
image: DecorationImage(
|
||||
child: Image(
|
||||
image: imageProvider,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
progressIndicatorBuilder: (context, url, progress) =>
|
||||
ShimmerPlaceholder(
|
||||
borderRadius: borderRadius,
|
||||
|
|
|
|||
44
pubspec.lock
44
pubspec.lock
|
|
@ -148,6 +148,48 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.1.2"
|
||||
firebase_core:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_core
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.13.1"
|
||||
firebase_core_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.2.5"
|
||||
firebase_core_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.6.1"
|
||||
firebase_messaging:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_messaging
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "11.2.8"
|
||||
firebase_messaging_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.2.1"
|
||||
firebase_messaging_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.9"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
|
|
@ -762,5 +804,5 @@ packages:
|
|||
source: hosted
|
||||
version: "5.3.1"
|
||||
sdks:
|
||||
dart: ">=2.15.0 <3.0.0"
|
||||
dart: ">=2.16.0 <3.0.0"
|
||||
flutter: ">=2.5.0"
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ dependencies:
|
|||
url_launcher: ^6.0.18
|
||||
audio_video_progress_bar: ^0.10.0
|
||||
image_cropper: ^1.5.0
|
||||
firebase_messaging: ^11.2.8
|
||||
firebase_core: ^1.13.1
|
||||
|
||||
|
||||
dev_dependencies:
|
||||
|
|
|
|||
Loading…
Reference in New Issue