├── ios ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ └── project.pbxproj ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist └── .gitignore ├── images ├── zaim.jpg └── icon_user.png ├── web ├── favicon.png ├── icons │ ├── Icon-192.png │ └── Icon-512.png ├── manifest.json └── index.html ├── android ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── values-night │ │ │ │ │ └── styles.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── newsly │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── google-services.json │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle └── build.gradle ├── .metadata ├── lib ├── main.dart ├── model │ ├── article.dart │ └── news.dart ├── view │ ├── widget │ │ ├── dateTimeField.dart │ │ ├── shimmerLoading.dart │ │ ├── card_widget.dart │ │ ├── dialog_widget.dart │ │ └── newsList.dart │ ├── page │ │ ├── sport │ │ │ ├── topHeadlinesSport.dart │ │ │ ├── breakNewsSport.dart │ │ │ └── sportNews.dart │ │ ├── health │ │ │ ├── topHeadlinesHealth.dart │ │ │ ├── breakNewsHealth.dart │ │ │ └── healthNews.dart │ │ ├── general │ │ │ ├── topHeadlineGeneral.dart │ │ │ ├── breakNewsGeneral.dart │ │ │ └── generalNews.dart │ │ ├── technology │ │ │ ├── topHeadlinesTechnology.dart │ │ │ ├── breakNewsTechnology.dart │ │ │ └── technologyNews.dart │ │ ├── business │ │ │ ├── topHeadlinesBusiness.dart │ │ │ ├── breakNewsBusiness.dart │ │ │ └── businessNews.dart │ │ └── articles │ │ │ ├── articles_page.dart │ │ │ ├── formAddArticle.dart │ │ │ └── formUpdateArticle.dart │ ├── splash.dart │ ├── detailNews.dart │ ├── drawer.dart │ ├── beranda.dart │ └── home.dart └── viewmodel │ └── service │ ├── api_service.dart │ └── firestore_service.dart ├── .gitignore ├── README.md ├── test └── widget_test.dart ├── pubspec.yaml └── pubspec.lock /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /images/zaim.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/images/zaim.jpg -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/web/favicon.png -------------------------------------------------------------------------------- /images/icon_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/images/icon_user.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/web/icons/Icon-512.png -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/newsly/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.newsly 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() 6 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MZaimM/Newsly-Flutter-App/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 7 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: d79295af24c3ed621c33713ecda14ad196fd9c31 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_core/firebase_core.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:newsly/view/splash.dart'; 4 | 5 | void main() { 6 | runApp(MyApp()); 7 | } 8 | 9 | class MyApp extends StatelessWidget { 10 | // This widget is the root of your application. 11 | @override 12 | Widget build(BuildContext context) { 13 | Firebase.initializeApp(); 14 | return MaterialApp( 15 | debugShowCheckedModeBanner: false, 16 | title: 'Newsly', 17 | theme: ThemeData( 18 | primarySwatch: Colors.blue, 19 | ), 20 | home:SplashScreen(), 21 | ); 22 | } 23 | } -------------------------------------------------------------------------------- /lib/model/article.dart: -------------------------------------------------------------------------------- 1 | class Article { 2 | String? id; 3 | String? title; 4 | String? date; 5 | String? author; 6 | String? urlArtikel; 7 | String? description; 8 | 9 | String? get deskripsi => description; 10 | 11 | set deskripsi(String? deskripsi) { 12 | description = deskripsi; 13 | } 14 | String? image; 15 | 16 | String? get gambar => image; 17 | 18 | set gambar(String? image) { 19 | image = image; 20 | } 21 | 22 | Article( 23 | {this.author, 24 | this.date, 25 | this.description, 26 | this.id, 27 | this.image, 28 | this.title, 29 | this.urlArtikel}); 30 | } 31 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "newsly", 3 | "short_name": "newsly", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/ephemeral/ 22 | Flutter/app.flx 23 | Flutter/app.zip 24 | Flutter/flutter_assets/ 25 | Flutter/flutter_export_environment.sh 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | classpath 'com.google.gms:google-services:4.3.10' 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | google() 18 | jcenter() 19 | } 20 | } 21 | 22 | rootProject.buildDir = '../build' 23 | subprojects { 24 | project.buildDir = "${rootProject.buildDir}/${project.name}" 25 | project.evaluationDependsOn(':app') 26 | } 27 | 28 | task clean(type: Delete) { 29 | delete rootProject.buildDir 30 | } 31 | -------------------------------------------------------------------------------- /lib/view/widget/dateTimeField.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:date_field/date_field.dart'; 3 | 4 | class DateTimeField extends StatelessWidget { 5 | DateTimeField({Key? key}) : super(key: key); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return DateTimeFormField( 10 | decoration: InputDecoration( 11 | hintText: "Date", 12 | labelText: "Date", 13 | prefixIcon: Icon(Icons.date_range_outlined), 14 | border: OutlineInputBorder(borderRadius: BorderRadius.circular(8.0))), 15 | mode: DateTimeFieldPickerMode.dateAndTime, 16 | autovalidateMode: AutovalidateMode.always, 17 | validator: (e) => (e?.day ?? 0) == 1 ? 'Please not the first day' : null, 18 | onDateSelected: (DateTime value) { 19 | print(value); 20 | }, 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Newsly Flutter App 2 | 3 | Newsly is an application built using the flutter framework. In this application, it has a feature to read news and add your own articles to the newsly application. Newsly uses the MVVM (Model-View-Viewmodel) architecture. On the backend side, the data is obtained from https://newsapi.org/ and uses firebase in its data storage. 4 | 5 | 6 | ![IG-1](https://user-images.githubusercontent.com/65083723/141663478-85c77dbe-ae14-4be3-896f-a9a7b3179428.png) 7 | ![IG-2](https://user-images.githubusercontent.com/65083723/141663479-07c5c54b-0cef-48d7-80fe-9c0b44f6eba6.png) 8 | 9 | 10 | ## Getting Started 11 | 12 | This project is a starting point for a Flutter application. 13 | 14 | A few resources to get you started if this is your first Flutter project: 15 | 16 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 17 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 18 | 19 | For help getting started with Flutter, view our 20 | [online documentation](https://flutter.dev/docs), which offers tutorials, 21 | samples, guidance on mobile development, and a full API reference. 22 | -------------------------------------------------------------------------------- /lib/view/page/sport/topHeadlinesSport.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:newsly/model/news.dart'; 3 | import 'package:newsly/viewmodel/service/api_service.dart'; 4 | import 'package:http/http.dart' as http; 5 | import 'package:newsly/view/widget/newsList.dart'; 6 | import 'package:newsly/view/widget/shimmerLoading.dart'; 7 | 8 | class TopHeadlinesSport extends StatelessWidget { 9 | const TopHeadlinesSport({ Key? key }) : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | ApiService api = ApiService(); 14 | 15 | return Container( 16 | child: FutureBuilder>( 17 | future: api.fetchNewsSport(http.Client()), 18 | builder: (context, snapshot) { 19 | if (snapshot.hasError) { 20 | return Center( 21 | child: Text("Pengambilan Data API Error"), 22 | ); 23 | }else if (snapshot.hasData){ 24 | return TopHeadlinesList(news: snapshot.data!); 25 | } 26 | return Center( 27 | child: ShimmerLoadingTopHead(), 28 | ); 29 | }, 30 | ), 31 | ); 32 | } 33 | } -------------------------------------------------------------------------------- /android/app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "517842577037", 4 | "project_id": "newsly-c7bc0", 5 | "storage_bucket": "newsly-c7bc0.appspot.com" 6 | }, 7 | "client": [ 8 | { 9 | "client_info": { 10 | "mobilesdk_app_id": "1:517842577037:android:53380392d1b80db4ace4c4", 11 | "android_client_info": { 12 | "package_name": "com.example.newsly" 13 | } 14 | }, 15 | "oauth_client": [ 16 | { 17 | "client_id": "517842577037-h7hbp2omei0hkbtbuu9q4p4fsuu7roji.apps.googleusercontent.com", 18 | "client_type": 3 19 | } 20 | ], 21 | "api_key": [ 22 | { 23 | "current_key": "AIzaSyD3GDyq0Ktg5LlqU90UkylJEtn0ErI1I6k" 24 | } 25 | ], 26 | "services": { 27 | "appinvite_service": { 28 | "other_platform_oauth_client": [ 29 | { 30 | "client_id": "517842577037-h7hbp2omei0hkbtbuu9q4p4fsuu7roji.apps.googleusercontent.com", 31 | "client_type": 3 32 | } 33 | ] 34 | } 35 | } 36 | } 37 | ], 38 | "configuration_version": "1" 39 | } -------------------------------------------------------------------------------- /lib/view/page/health/topHeadlinesHealth.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:newsly/model/news.dart'; 3 | import 'package:newsly/viewmodel/service/api_service.dart'; 4 | import 'package:newsly/view/widget/newsList.dart'; 5 | import 'package:http/http.dart' as http; 6 | import 'package:newsly/view/widget/shimmerLoading.dart'; 7 | 8 | class TopHeadlinesHealth extends StatelessWidget { 9 | const TopHeadlinesHealth({ Key? key }) : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | ApiService api = ApiService(); 14 | 15 | return Container( 16 | child: FutureBuilder>( 17 | future: api.fetchNewsHealth(http.Client()), 18 | builder: (context, snapshot) { 19 | if (snapshot.hasError) { 20 | return Center( 21 | child: Text("Pengambilan Data API Error"), 22 | ); 23 | }else if (snapshot.hasData){ 24 | return TopHeadlinesList(news: snapshot.data!); 25 | } 26 | return Center( 27 | child: ShimmerLoadingTopHead(), 28 | ); 29 | }, 30 | ), 31 | ); 32 | } 33 | } -------------------------------------------------------------------------------- /lib/view/page/general/topHeadlineGeneral.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:http/http.dart' as http; 3 | import 'package:newsly/model/news.dart'; 4 | import 'package:newsly/viewmodel/service/api_service.dart'; 5 | import 'package:newsly/view/widget/newsList.dart'; 6 | import 'package:newsly/view/widget/shimmerLoading.dart'; 7 | 8 | class TopHeadlinesGeneral extends StatelessWidget { 9 | const TopHeadlinesGeneral({ Key? key }) : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | ApiService api = ApiService(); 14 | 15 | return Container( 16 | child: FutureBuilder>( 17 | future: api.fetchNewsGeneral(http.Client()), 18 | builder: (context, snapshot) { 19 | if (snapshot.hasError) { 20 | return Center( 21 | child: Text("Pengambilan Data API Error"), 22 | ); 23 | }else if (snapshot.hasData){ 24 | return TopHeadlinesList(news: snapshot.data!); 25 | } 26 | return Center( 27 | child: ShimmerLoadingTopHead(), 28 | ); 29 | }, 30 | ), 31 | ); 32 | } 33 | } -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:newsly/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /lib/view/page/sport/breakNewsSport.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:newsly/model/news.dart'; 3 | import 'package:newsly/viewmodel/service/api_service.dart'; 4 | import 'package:http/http.dart' as http; 5 | import 'package:newsly/view/widget/newsList.dart'; 6 | import 'package:newsly/view/widget/shimmerLoading.dart'; 7 | 8 | class BreakNewsSport extends StatelessWidget { 9 | const BreakNewsSport({ Key? key }) : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | ApiService api = ApiService(); 14 | 15 | return Container( 16 | height: 270, 17 | child: FutureBuilder>( 18 | future: api.fetchNewsSport(http.Client()), 19 | builder: (context, snapshot) { 20 | if (snapshot.hasError) { 21 | return Center( 22 | child: Text("Pengambilan Data API Error"), 23 | ); 24 | }else if (snapshot.hasData){ 25 | return BreakNewsList(news: snapshot.data!); 26 | } 27 | return Center( 28 | child: ShimmerLoadingBreakNews(), 29 | ); 30 | }, 31 | ), 32 | ); 33 | } 34 | } -------------------------------------------------------------------------------- /lib/view/page/health/breakNewsHealth.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:newsly/model/news.dart'; 3 | import 'package:newsly/viewmodel/service/api_service.dart'; 4 | import 'package:http/http.dart' as http; 5 | import 'package:newsly/view/widget/newsList.dart'; 6 | import 'package:newsly/view/widget/shimmerLoading.dart'; 7 | 8 | class BreakNewsHealth extends StatelessWidget { 9 | const BreakNewsHealth({ Key? key }) : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | ApiService api = ApiService(); 14 | 15 | return Container( 16 | height: 270, 17 | child: FutureBuilder>( 18 | future: api.fetchNewsHealth(http.Client()), 19 | builder: (context, snapshot) { 20 | if (snapshot.hasError) { 21 | return Center( 22 | child: Text("Pengambilan Data API Error"), 23 | ); 24 | }else if (snapshot.hasData){ 25 | return BreakNewsList(news: snapshot.data!); 26 | } 27 | return Center( 28 | child: ShimmerLoadingBreakNews(), 29 | ); 30 | }, 31 | ), 32 | ); 33 | } 34 | } -------------------------------------------------------------------------------- /lib/view/page/technology/topHeadlinesTechnology.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:newsly/model/news.dart'; 3 | import 'package:newsly/viewmodel/service/api_service.dart'; 4 | import 'package:http/http.dart' as http; 5 | import 'package:newsly/view/widget/newsList.dart'; 6 | import 'package:newsly/view/widget/shimmerLoading.dart'; 7 | 8 | class TopHeadlinesTechnology extends StatelessWidget { 9 | const TopHeadlinesTechnology({ Key? key }) : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | ApiService api = ApiService(); 14 | 15 | return Container( 16 | child: FutureBuilder>( 17 | future: api.fetchNewsTechnology(http.Client()), 18 | builder: (context, snapshot) { 19 | if (snapshot.hasError) { 20 | return Center( 21 | child: Text("Pengambilan Data API Error"), 22 | ); 23 | }else if (snapshot.hasData){ 24 | return TopHeadlinesList(news: snapshot.data!); 25 | } 26 | return Center( 27 | child: ShimmerLoadingTopHead(), 28 | ); 29 | }, 30 | ), 31 | ); 32 | } 33 | } -------------------------------------------------------------------------------- /lib/view/page/general/breakNewsGeneral.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:newsly/model/news.dart'; 3 | import 'package:newsly/viewmodel/service/api_service.dart'; 4 | import 'package:http/http.dart' as http; 5 | import 'package:newsly/view/widget/newsList.dart'; 6 | import 'package:newsly/view/widget/shimmerLoading.dart'; 7 | 8 | class BreakNewsGeneral extends StatelessWidget { 9 | const BreakNewsGeneral({ Key? key }) : super(key: key); 10 | 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | ApiService api = ApiService(); 15 | 16 | return Container( 17 | height: 270, 18 | child: FutureBuilder>( 19 | future: api.fetchNewsGeneral(http.Client()), 20 | builder: (context, snapshot) { 21 | if (snapshot.hasError) { 22 | return Center( 23 | child: Text("Pengambilan Data API Error"), 24 | ); 25 | }else if (snapshot.hasData){ 26 | return BreakNewsList(news: snapshot.data!); 27 | } 28 | return Center( 29 | child: ShimmerLoadingBreakNews(), 30 | ); 31 | }, 32 | ), 33 | ); 34 | } 35 | } -------------------------------------------------------------------------------- /lib/view/splash.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:animated_splash_screen/animated_splash_screen.dart'; 3 | import 'package:newsly/view/beranda.dart'; 4 | import 'package:page_transition/page_transition.dart'; 5 | import 'package:shimmer/shimmer.dart'; 6 | 7 | class SplashScreen extends StatelessWidget { 8 | const SplashScreen({Key? key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return MaterialApp( 13 | debugShowCheckedModeBanner: false, 14 | home: AnimatedSplashScreen( 15 | splash: Shimmer.fromColors( 16 | baseColor: Colors.white, 17 | highlightColor: Colors.lightBlue, 18 | child: Center( 19 | child: Text( 20 | "Newsly", 21 | style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), 22 | ), 23 | ), 24 | ), 25 | nextScreen: Beranda(), 26 | duration: 2000, 27 | splashTransition: SplashTransition.fadeTransition, 28 | pageTransitionType: PageTransitionType.fade, 29 | backgroundColor: Colors.blue, 30 | ), 31 | ); 32 | } 33 | } 34 | 35 | 36 | -------------------------------------------------------------------------------- /lib/view/page/technology/breakNewsTechnology.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:newsly/model/news.dart'; 3 | import 'package:newsly/viewmodel/service/api_service.dart'; 4 | import 'package:newsly/view/widget/newsList.dart'; 5 | import 'package:http/http.dart' as http; 6 | import 'package:newsly/view/widget/shimmerLoading.dart'; 7 | 8 | class BreakNewsTechnology extends StatelessWidget { 9 | const BreakNewsTechnology({ Key? key }) : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | ApiService api = ApiService(); 14 | 15 | return Container( 16 | height: 270, 17 | child: FutureBuilder>( 18 | future: api.fetchNewsTechnology(http.Client()), 19 | builder: (context, snapshot) { 20 | if (snapshot.hasError) { 21 | return Center( 22 | child: Text("Pengambilan Data API Error"), 23 | ); 24 | }else if (snapshot.hasData){ 25 | return BreakNewsList(news: snapshot.data!); 26 | } 27 | return Center( 28 | child: ShimmerLoadingBreakNews(), 29 | ); 30 | }, 31 | ), 32 | ); 33 | } 34 | } -------------------------------------------------------------------------------- /lib/view/page/business/topHeadlinesBusiness.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:newsly/model/news.dart'; 3 | import 'package:newsly/viewmodel/service/api_service.dart'; 4 | import 'package:newsly/view/widget/newsList.dart'; 5 | import 'package:http/http.dart' as http; 6 | import 'package:newsly/view/widget/shimmerLoading.dart'; 7 | 8 | class TopHeadlinesBusiness extends StatefulWidget { 9 | const TopHeadlinesBusiness({ Key? key }) : super(key: key); 10 | 11 | @override 12 | _TopHeadlinesBusinessState createState() => _TopHeadlinesBusinessState(); 13 | } 14 | 15 | class _TopHeadlinesBusinessState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | ApiService api = ApiService(); 19 | 20 | return Container( 21 | child: FutureBuilder>( 22 | future: api.fetchNewsBusiness(http.Client()), 23 | builder: (context, snapshot) { 24 | if (snapshot.hasError) { 25 | return Center( 26 | child: Text("Pengambilan Data API Error"), 27 | ); 28 | }else if (snapshot.hasData){ 29 | return TopHeadlinesList(news: snapshot.data!); 30 | } 31 | return Center( 32 | child: ShimmerLoadingTopHead(), 33 | ); 34 | }, 35 | ), 36 | ); 37 | } 38 | } -------------------------------------------------------------------------------- /lib/view/page/business/breakNewsBusiness.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:newsly/model/news.dart'; 3 | import 'package:newsly/viewmodel/service/api_service.dart'; 4 | import 'package:http/http.dart' as http; 5 | import 'package:newsly/view/widget/newsList.dart'; 6 | import 'package:newsly/view/widget/shimmerLoading.dart'; 7 | 8 | class BreakNewsBusiness extends StatefulWidget { 9 | const BreakNewsBusiness({ Key? key }) : super(key: key); 10 | 11 | @override 12 | _BreakNewsBusinessState createState() => _BreakNewsBusinessState(); 13 | } 14 | 15 | class _BreakNewsBusinessState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | ApiService api = ApiService(); 19 | 20 | return Container( 21 | height: 270, 22 | child: FutureBuilder>( 23 | future: api.fetchNewsBusiness(http.Client()), 24 | builder: (context, snapshot) { 25 | if (snapshot.hasError) { 26 | return Center( 27 | child: Text("Pengambilan Data API Error"), 28 | ); 29 | }else if (snapshot.hasData){ 30 | return BreakNewsList(news: snapshot.data!); 31 | } 32 | return Center( 33 | child: ShimmerLoadingBreakNews(), 34 | ); 35 | }, 36 | ), 37 | ); 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /lib/view/detailNews.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:webview_flutter/webview_flutter.dart'; 5 | 6 | class DetailNews extends StatelessWidget { 7 | String? author; 8 | String? title; 9 | String? image; 10 | String? published; 11 | String? content; 12 | String? url; 13 | String? source; 14 | Completer _controller = Completer(); 15 | 16 | DetailNews( 17 | {Key? key, 18 | this.author, 19 | this.title, 20 | this.image, 21 | this.published, 22 | this.content, 23 | this.url, 24 | this.source}) 25 | : super(key: key); 26 | 27 | @override 28 | Widget build(BuildContext context) { 29 | return Scaffold( 30 | appBar: AppBar( 31 | backgroundColor: Colors.white, 32 | elevation: 0, 33 | title: Text( 34 | source!, 35 | style: TextStyle(color: Colors.blue), 36 | ), 37 | leading: IconButton( 38 | icon: Icon( 39 | Icons.arrow_back, 40 | color: Colors.black, 41 | ), 42 | onPressed: () { 43 | Navigator.pop(context); 44 | }, 45 | ), 46 | ), 47 | backgroundColor: Colors.white, 48 | body: WebView( 49 | initialUrl: url, 50 | javascriptMode: JavascriptMode.unrestricted, 51 | onWebViewCreated: (WebViewController webViewController) { 52 | _controller.complete(webViewController); 53 | }, 54 | )); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/view/drawer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DrawerMenu extends StatelessWidget { 4 | const DrawerMenu({ Key? key }) : super(key: key); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Drawer( 9 | child: ListView( 10 | children: [ 11 | UserAccountsDrawerHeader( 12 | currentAccountPicture: Container( 13 | child: Image.asset('images/icon_user.png'), 14 | ), 15 | accountName: Text('Muhammad Zaim Maulana'), 16 | accountEmail: Text('19650058@student.uin-malang.ac.id')), 17 | ListTile( 18 | leading: Icon(Icons.home), 19 | title: Text('Beranda'), 20 | onTap: (){ 21 | }, 22 | ), 23 | ListTile( 24 | leading: Icon(Icons.devices), 25 | title: Text('Technology'), 26 | onTap: (){ 27 | 28 | }, 29 | ), 30 | ListTile( 31 | leading: Icon(Icons.business), 32 | title: Text('Business'), 33 | onTap: (){ 34 | 35 | }, 36 | ), 37 | ListTile( 38 | leading: Icon(Icons.health_and_safety), 39 | title: Text('Healthy'), 40 | onTap: (){ 41 | 42 | }, 43 | ), 44 | ListTile( 45 | leading: Icon(Icons.sports), 46 | title: Text('Sports'), 47 | onTap: (){ 48 | 49 | }, 50 | ), 51 | ], 52 | ), 53 | ); 54 | } 55 | } -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | newsly 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /lib/view/page/sport/sportNews.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hexcolor/hexcolor.dart'; 3 | import 'package:newsly/view/page/sport/breakNewsSport.dart'; 4 | import 'package:newsly/view/page/sport/topHeadlinesSport.dart'; 5 | 6 | class SportNews extends StatelessWidget { 7 | const SportNews({ Key? key }) : super(key: key); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Container( 12 | margin: EdgeInsets.only(top: 16), 13 | child: SingleChildScrollView( 14 | child: Column( 15 | mainAxisSize: MainAxisSize.min, 16 | crossAxisAlignment: CrossAxisAlignment.start, 17 | children: [ 18 | Container( 19 | margin: EdgeInsets.only(left: 16), 20 | child: Text( 21 | 'Breaking News', 22 | style: TextStyle( 23 | fontSize: 24, 24 | fontWeight: FontWeight.bold, 25 | color: HexColor('#4E3A55')), 26 | ), 27 | ), 28 | SizedBox( 29 | height: 16, 30 | ), 31 | BreakNewsSport(), 32 | SizedBox( 33 | height: 24, 34 | ), 35 | Container( 36 | margin: EdgeInsets.only(left: 16), 37 | child: Text( 38 | 'Top Headlines', 39 | style: TextStyle( 40 | fontSize: 24, 41 | fontWeight: FontWeight.bold, 42 | color: HexColor('#4E3A55')), 43 | ), 44 | ), 45 | SizedBox( 46 | height: 16, 47 | ), 48 | TopHeadlinesSport() 49 | ], 50 | ), 51 | )); 52 | } 53 | } -------------------------------------------------------------------------------- /lib/view/page/health/healthNews.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hexcolor/hexcolor.dart'; 3 | import 'package:newsly/view/page/health/breakNewsHealth.dart'; 4 | import 'package:newsly/view/page/health/topHeadlinesHealth.dart'; 5 | 6 | class HealthNews extends StatelessWidget { 7 | const HealthNews({ Key? key }) : super(key: key); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Container( 12 | margin: EdgeInsets.only(top: 16), 13 | child: SingleChildScrollView( 14 | child: Column( 15 | mainAxisSize: MainAxisSize.min, 16 | crossAxisAlignment: CrossAxisAlignment.start, 17 | children: [ 18 | Container( 19 | margin: EdgeInsets.only(left: 16), 20 | child: Text( 21 | 'Breaking News', 22 | style: TextStyle( 23 | fontSize: 24, 24 | fontWeight: FontWeight.bold, 25 | color: HexColor('#4E3A55')), 26 | ), 27 | ), 28 | SizedBox( 29 | height: 16, 30 | ), 31 | BreakNewsHealth(), 32 | SizedBox( 33 | height: 24, 34 | ), 35 | Container( 36 | margin: EdgeInsets.only(left: 16), 37 | child: Text( 38 | 'Top Headlines', 39 | style: TextStyle( 40 | fontSize: 24, 41 | fontWeight: FontWeight.bold, 42 | color: HexColor('#4E3A55')), 43 | ), 44 | ), 45 | SizedBox( 46 | height: 16, 47 | ), 48 | TopHeadlinesHealth() 49 | ], 50 | ), 51 | )); 52 | } 53 | } -------------------------------------------------------------------------------- /lib/view/page/general/generalNews.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hexcolor/hexcolor.dart'; 3 | import 'package:newsly/view/page/general/breakNewsGeneral.dart'; 4 | import 'package:newsly/view/page/general/topHeadlineGeneral.dart'; 5 | 6 | class GeneralNews extends StatelessWidget { 7 | const GeneralNews({ Key? key }) : super(key: key); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Container( 12 | margin: EdgeInsets.only(top: 16), 13 | child: SingleChildScrollView( 14 | child: Column( 15 | mainAxisSize: MainAxisSize.min, 16 | crossAxisAlignment: CrossAxisAlignment.start, 17 | children: [ 18 | Container( 19 | margin: EdgeInsets.only(left: 16), 20 | child: Text( 21 | 'Breaking News', 22 | style: TextStyle( 23 | fontSize: 24, 24 | fontWeight: FontWeight.bold, 25 | color: HexColor('#4E3A55')), 26 | ), 27 | ), 28 | SizedBox( 29 | height: 16, 30 | ), 31 | BreakNewsGeneral(), 32 | SizedBox( 33 | height: 24, 34 | ), 35 | Container( 36 | margin: EdgeInsets.only(left: 16), 37 | child: Text( 38 | 'Top Headlines', 39 | style: TextStyle( 40 | fontSize: 24, 41 | fontWeight: FontWeight.bold, 42 | color: HexColor('#4E3A55')), 43 | ), 44 | ), 45 | SizedBox( 46 | height: 16, 47 | ), 48 | TopHeadlinesGeneral() 49 | ], 50 | ), 51 | )); 52 | } 53 | } -------------------------------------------------------------------------------- /lib/view/page/business/businessNews.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hexcolor/hexcolor.dart'; 3 | import 'package:newsly/view/page/business/breakNewsBusiness.dart'; 4 | import 'package:newsly/view/page/business/topHeadlinesBusiness.dart'; 5 | 6 | class BusinessNews extends StatelessWidget { 7 | const BusinessNews({ Key? key }) : super(key: key); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Container( 12 | margin: EdgeInsets.only(top: 16), 13 | child: SingleChildScrollView( 14 | child: Column( 15 | mainAxisSize: MainAxisSize.min, 16 | crossAxisAlignment: CrossAxisAlignment.start, 17 | children: [ 18 | Container( 19 | margin: EdgeInsets.only(left: 16), 20 | child: Text( 21 | 'Breaking News', 22 | style: TextStyle( 23 | fontSize: 24, 24 | fontWeight: FontWeight.bold, 25 | color: HexColor('#4E3A55')), 26 | ), 27 | ), 28 | SizedBox( 29 | height: 16, 30 | ), 31 | BreakNewsBusiness(), 32 | SizedBox( 33 | height: 24, 34 | ), 35 | Container( 36 | margin: EdgeInsets.only(left: 16), 37 | child: Text( 38 | 'Top Headlines', 39 | style: TextStyle( 40 | fontSize: 24, 41 | fontWeight: FontWeight.bold, 42 | color: HexColor('#4E3A55')), 43 | ), 44 | ), 45 | SizedBox( 46 | height: 16, 47 | ), 48 | TopHeadlinesBusiness() 49 | ], 50 | ), 51 | )); 52 | } 53 | } -------------------------------------------------------------------------------- /lib/view/page/technology/technologyNews.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hexcolor/hexcolor.dart'; 3 | import 'package:newsly/view/page/technology/breakNewsTechnology.dart'; 4 | import 'package:newsly/view/page/technology/topHeadlinesTechnology.dart'; 5 | 6 | class TechnologyNews extends StatelessWidget { 7 | const TechnologyNews({ Key? key }) : super(key: key); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Container( 12 | margin: EdgeInsets.only(top: 16), 13 | child: SingleChildScrollView( 14 | child: Column( 15 | mainAxisSize: MainAxisSize.min, 16 | crossAxisAlignment: CrossAxisAlignment.start, 17 | children: [ 18 | Container( 19 | margin: EdgeInsets.only(left: 16), 20 | child: Text( 21 | 'Breaking News', 22 | style: TextStyle( 23 | fontSize: 24, 24 | fontWeight: FontWeight.bold, 25 | color: HexColor('#4E3A55')), 26 | ), 27 | ), 28 | SizedBox( 29 | height: 16, 30 | ), 31 | BreakNewsTechnology(), 32 | SizedBox( 33 | height: 24, 34 | ), 35 | Container( 36 | margin: EdgeInsets.only(left: 16), 37 | child: Text( 38 | 'Top Headlines', 39 | style: TextStyle( 40 | fontSize: 24, 41 | fontWeight: FontWeight.bold, 42 | color: HexColor('#4E3A55')), 43 | ), 44 | ), 45 | SizedBox( 46 | height: 16, 47 | ), 48 | TopHeadlinesTechnology() 49 | ], 50 | ), 51 | )); 52 | } 53 | } -------------------------------------------------------------------------------- /lib/viewmodel/service/api_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:http/http.dart' as http; 4 | import 'package:newsly/model/news.dart'; 5 | 6 | class ApiService{ 7 | late String _category; 8 | String _country = "id"; 9 | String _apiKey2 = "2321d66b033643c59f2179c5a077da24"; 10 | String _baseUrl = "https://newsapi.org/v2/"; 11 | 12 | List parseNews(String responseBody){ 13 | final parsed = jsonDecode(responseBody); 14 | final jsonObject = (parsed as Map)["articles"]; 15 | return jsonObject.map((json) => News.fromJson(json)).toList(); 16 | } 17 | 18 | // Fetch News General 19 | Future> fetchNewsGeneral(http.Client client) async { 20 | _category = "general"; 21 | final response = await client.get( 22 | Uri.parse('${_baseUrl}top-headlines?country=$_country&category=$_category&apiKey=$_apiKey2') 23 | ); 24 | return parseNews(response.body); 25 | } 26 | Future> fetchNewsSport(http.Client client) async { 27 | _category = "sport"; 28 | final response = await client.get( 29 | Uri.parse('${_baseUrl}top-headlines?country=$_country&category=$_category&apiKey=$_apiKey2') 30 | ); 31 | return parseNews(response.body); 32 | } 33 | Future> fetchNewsHealth(http.Client client) async { 34 | _category = "health"; 35 | final response = await client.get( 36 | Uri.parse('${_baseUrl}top-headlines?country=$_country&category=$_category&apiKey=$_apiKey2') 37 | ); 38 | return parseNews(response.body); 39 | } 40 | Future> fetchNewsBusiness(http.Client client) async { 41 | _category = "business"; 42 | final response = await client.get( 43 | Uri.parse('${_baseUrl}top-headlines?country=$_country&category=$_category&apiKey=$_apiKey2') 44 | ); 45 | return parseNews(response.body); 46 | } 47 | Future> fetchNewsTechnology(http.Client client) async { 48 | _category = "technology"; 49 | final response = await client.get( 50 | Uri.parse('${_baseUrl}top-headlines?country=$_country&category=$_category&apiKey=$_apiKey2') 51 | ); 52 | return parseNews(response.body); 53 | } 54 | 55 | 56 | } -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 9 | 16 | 20 | 24 | 29 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /lib/viewmodel/service/firestore_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_firestore/cloud_firestore.dart'; 2 | import 'package:firebase_core/firebase_core.dart'; 3 | 4 | final FirebaseFirestore _firestore = FirebaseFirestore.instance; 5 | final CollectionReference _reference = _firestore.collection('articles'); 6 | 7 | class FirestoreService { 8 | static Future addItem( 9 | {required String title, 10 | required String author, 11 | required String published, 12 | required String urlArticle, 13 | required String description, 14 | required String image, 15 | required String id}) async { 16 | DocumentReference documentReferencer = _reference.doc(); 17 | 18 | Map data = { 19 | "title": title, 20 | "author": author, 21 | "published": published, 22 | "url": urlArticle, 23 | "description": description, 24 | "image": image, 25 | "id" : id 26 | }; 27 | 28 | await documentReferencer 29 | .set(data) 30 | .whenComplete(() => print("Data Artikel berhasil Ditambahkan")) 31 | .catchError((e) => print(e)); 32 | } 33 | 34 | static Stream readItems() { 35 | CollectionReference readReference = _reference; 36 | return readReference.snapshots(); 37 | } 38 | 39 | static Future updateItem( 40 | {required String title, 41 | required String author, 42 | required String published, 43 | required String urlArticle, 44 | required String description, 45 | required String id, required String image}) async { 46 | await Firebase.initializeApp(); 47 | DocumentReference documentReferencer = _reference.doc(id); 48 | 49 | Map data = { 50 | "title": title, 51 | "author": author, 52 | "published": published, 53 | "url": urlArticle, 54 | "description": description, 55 | "image" : image 56 | }; 57 | 58 | await documentReferencer 59 | .update(data) 60 | .whenComplete(() => print("Data Artikel berhasil Diupdate")) 61 | .catchError((e) => print(e)); 62 | } 63 | 64 | static Future deleteItem({required String id}) async { 65 | DocumentReference documentReference = _reference.doc(id); 66 | 67 | await documentReference 68 | .delete() 69 | .whenComplete(() => print("Data berhasil dihapus")) 70 | .catchError((e) => print("Data gagal dihapus")); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | def keystoreProperties = new Properties() 29 | def keystorePropertiesFile = rootProject.file('key.properties') 30 | if (keystorePropertiesFile.exists()) { 31 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) 32 | } 33 | 34 | android { 35 | compileSdkVersion 30 36 | 37 | sourceSets { 38 | main.java.srcDirs += 'src/main/kotlin' 39 | } 40 | 41 | defaultConfig { 42 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 43 | applicationId "com.example.newsly" 44 | minSdkVersion 19 45 | targetSdkVersion 30 46 | multiDexEnabled true 47 | versionCode flutterVersionCode.toInteger() 48 | versionName flutterVersionName 49 | } 50 | 51 | signingConfigs { 52 | release { 53 | keyAlias keystoreProperties['keyAlias'] 54 | keyPassword keystoreProperties['keyPassword'] 55 | storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null 56 | storePassword keystoreProperties['storePassword'] 57 | } 58 | } 59 | 60 | buildTypes { 61 | release { 62 | // TODO: Add your own signing config for the release build. 63 | // Signing with the debug keys for now, so `flutter run --release` works. 64 | // signingConfig signingConfigs.debug 65 | signingConfig signingConfigs.release 66 | } 67 | } 68 | } 69 | 70 | flutter { 71 | source '../..' 72 | } 73 | 74 | dependencies { 75 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 76 | implementation platform('com.google.firebase:firebase-bom:29.0.0') 77 | implementation 'com.google.firebase:firebase-analytics' 78 | implementation "androidx.multidex:multidex:2.0.1" 79 | } 80 | 81 | apply plugin: 'com.google.gms.google-services' 82 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: newsly 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | dependencies: 24 | animated_splash_screen: ^1.1.0 25 | cloud_firestore: ^3.1.0 26 | cupertino_icons: ^1.0.2 27 | date_field: ^2.1.2 28 | firebase_core: ^1.10.0 29 | firebase_storage: ^10.1.0 30 | flutter: 31 | sdk: flutter 32 | flutter_svg: ^0.22.0 33 | hexcolor: ^2.0.5 34 | http: ^0.13.3 35 | image_picker: ^0.8.4+4 36 | shimmer: ^2.0.0 37 | webview_flutter: ^2.0.13 38 | 39 | dev_dependencies: 40 | flutter_test: 41 | sdk: flutter 42 | 43 | # For information on the generic Dart part of this file, see the 44 | # following page: https://dart.dev/tools/pub/pubspec 45 | # The following section is specific to Flutter. 46 | flutter: 47 | 48 | # The following line ensures that the Material Icons font is 49 | # included with your application, so that you can use the icons in 50 | # the material Icons class. 51 | uses-material-design: true 52 | 53 | # To add assets to your application, add an assets section, like this: 54 | assets: 55 | - images/ 56 | # An image asset can refer to one or more resolution-specific "variants", see 57 | # https://flutter.dev/assets-and-images/#resolution-aware. 58 | # For details regarding adding assets from package dependencies, see 59 | # https://flutter.dev/assets-and-images/#from-packages 60 | # To add custom fonts to your application, add a fonts section here, 61 | # in this "flutter" section. Each entry in this list should have a 62 | # "family" key with the font family name, and a "fonts" key with a 63 | # list giving the asset and other descriptors for the font. For 64 | # example: 65 | # fonts: 66 | # - family: Schyler 67 | # fonts: 68 | # - asset: fonts/Schyler-Regular.ttf 69 | # - asset: fonts/Schyler-Italic.ttf 70 | # style: italic 71 | # - family: Trajan Pro 72 | # fonts: 73 | # - asset: fonts/TrajanPro.ttf 74 | # - asset: fonts/TrajanPro_Bold.ttf 75 | # weight: 700 76 | # 77 | # For details regarding fonts from package dependencies, 78 | # see https://flutter.dev/custom-fonts/#from-packages 79 | -------------------------------------------------------------------------------- /lib/view/widget/shimmerLoading.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:shimmer/shimmer.dart'; 3 | 4 | class ShimmerLoadingBreakNews extends StatelessWidget { 5 | const ShimmerLoadingBreakNews({ Key? key }) : super(key: key); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return Shimmer.fromColors( 10 | baseColor: Colors.grey, 11 | highlightColor: Colors.white70, 12 | child: ListView.builder( 13 | itemCount: 10, 14 | shrinkWrap: true, 15 | scrollDirection: Axis.horizontal, 16 | itemBuilder: (_, __){ 17 | return Container( 18 | width: 304, 19 | child: Padding( 20 | padding: const EdgeInsets.only(left: 16), 21 | child: Card( 22 | shape: RoundedRectangleBorder( 23 | borderRadius: BorderRadius.circular(20), 24 | ), 25 | child: Container( 26 | child: Column( 27 | crossAxisAlignment: CrossAxisAlignment.start, 28 | children: [ 29 | Container( 30 | height: 144, 31 | margin: 32 | EdgeInsets.only(top: 16, left: 16, right: 16), 33 | 34 | ), 35 | SizedBox( 36 | height: 12, 37 | ), 38 | Container( 39 | height: 70, 40 | margin: EdgeInsets.only(left: 16, right: 16), 41 | 42 | ) 43 | ], 44 | ))), 45 | ), 46 | ); 47 | }, 48 | ), 49 | ); 50 | } 51 | } 52 | 53 | class ShimmerLoadingTopHead extends StatelessWidget { 54 | const ShimmerLoadingTopHead({ Key? key }) : super(key: key); 55 | 56 | @override 57 | Widget build(BuildContext context) { 58 | return Shimmer.fromColors( 59 | baseColor: Colors.grey, 60 | highlightColor: Colors.white70, 61 | child: ListView.builder( 62 | physics: NeverScrollableScrollPhysics(), 63 | shrinkWrap: true, 64 | itemCount: 10, 65 | reverse: true, 66 | itemBuilder: (context, index) { 67 | return Container( 68 | margin: EdgeInsets.only(left: 16, right: 16, bottom: 12), 69 | height: 120, 70 | child: Card( 71 | child: Row( 72 | children: [ 73 | Container( 74 | width: 73, 75 | height: 77, 76 | margin: 77 | EdgeInsets.only(left: 16, top: 16, bottom: 16), 78 | 79 | ), 80 | SizedBox( 81 | width: 16, 82 | ), 83 | Container( 84 | margin: EdgeInsets.only(top: 16, bottom: 16), 85 | width: 206, 86 | ) 87 | ], 88 | ), 89 | ), 90 | ); 91 | }), 92 | ); 93 | } 94 | } -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /lib/view/beranda.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | import 'package:newsly/view/home.dart'; 4 | import 'package:newsly/view/page/articles/articles_page.dart'; 5 | import 'package:newsly/view/page/articles/formAddArticle.dart'; 6 | 7 | class Beranda extends StatefulWidget { 8 | const Beranda({ Key? key }) : super(key: key); 9 | 10 | @override 11 | _BerandaState createState() => _BerandaState(); 12 | } 13 | 14 | class _BerandaState extends State { 15 | int currentTab = 0; 16 | final PageStorageBucket bucket = PageStorageBucket(); 17 | Widget currentScreen = Home(); 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return Scaffold( 22 | body: PageStorage(bucket: bucket,child: currentScreen,), 23 | floatingActionButton: FloatingActionButton( 24 | onPressed: () { 25 | Navigator.push(context, MaterialPageRoute(builder: (context)=> FormAddArticle())); 26 | }, 27 | child: Icon(Icons.note_add), 28 | ), 29 | floatingActionButtonLocation: 30 | FloatingActionButtonLocation.centerDocked, 31 | bottomNavigationBar: BottomAppBar( 32 | elevation: 16, 33 | shape: CircularNotchedRectangle(), 34 | notchMargin: 5, 35 | child: Container( 36 | height: 60, 37 | child: Row( 38 | mainAxisAlignment: MainAxisAlignment.spaceAround, 39 | children: [ 40 | MaterialButton( 41 | onPressed: () { 42 | setState( 43 | () { 44 | currentScreen = Home(); 45 | currentTab = 0; 46 | }, 47 | ); 48 | }, 49 | child: Column( 50 | mainAxisAlignment: MainAxisAlignment.center, 51 | children: [ 52 | Icon( 53 | Icons.home, 54 | color: currentTab == 0 ? Colors.blue : Colors.grey, 55 | ), 56 | Text( 57 | "Home", 58 | style: TextStyle( 59 | color: 60 | currentTab == 0 ? Colors.blue : Colors.grey), 61 | ) 62 | ], 63 | ), 64 | ), 65 | MaterialButton( 66 | onPressed: () { 67 | setState(() { 68 | currentScreen = ArticlesPage(); 69 | currentTab = 1; 70 | }); 71 | }, 72 | child: Column( 73 | mainAxisAlignment: MainAxisAlignment.center, 74 | children: [ 75 | Icon( 76 | Icons.article, 77 | color: currentTab == 1 78 | ? Colors.blue 79 | : Colors.grey, 80 | ), 81 | Text( 82 | "Articles", 83 | style: TextStyle( 84 | color: currentTab == 1 85 | ? Colors.blue 86 | : Colors.grey), 87 | ) 88 | ], 89 | ), 90 | ) 91 | ], 92 | ), 93 | ), 94 | ), 95 | ); 96 | } 97 | } -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | newsly 27 | 28 | 29 | 30 | 33 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /lib/view/widget/card_widget.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:hexcolor/hexcolor.dart'; 5 | import 'package:newsly/view/detailNews.dart'; 6 | import 'package:newsly/view/widget/dialog_widget.dart'; 7 | 8 | class ItemCard extends StatelessWidget { 9 | String title; 10 | String published; 11 | String author; 12 | String urlArtikel; 13 | String description; 14 | String image; 15 | String id; 16 | 17 | ItemCard( 18 | {Key? key, 19 | required this.author, 20 | required this.title, 21 | required this.published, 22 | required this.description, 23 | required this.image, 24 | required this.urlArtikel, 25 | required this.id}) 26 | : super(key: key); 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return GestureDetector( 31 | onTap: () { 32 | Navigator.push( 33 | context, 34 | MaterialPageRoute( 35 | builder: (contex) => DetailNews( 36 | source: author, 37 | url: urlArtikel, 38 | ))); 39 | }, 40 | onLongPress: () { 41 | showDialog( 42 | context: context, 43 | builder: (context) { 44 | return DetailDialog( 45 | image: image, 46 | author: author, 47 | published: published, 48 | title: title, 49 | description: description, 50 | id: id, 51 | urlArtikel: urlArtikel, 52 | ); 53 | }); 54 | }, 55 | child: Container( 56 | width: double.infinity, 57 | child: Padding( 58 | padding: const EdgeInsets.only(left: 8.0, right: 8.0), 59 | child: Card( 60 | elevation: 1, 61 | shadowColor: Colors.blue, 62 | shape: RoundedRectangleBorder( 63 | borderRadius: BorderRadius.circular(8.0), 64 | ), 65 | child: Container( 66 | child: Column( 67 | crossAxisAlignment: CrossAxisAlignment.start, 68 | children: [ 69 | Container( 70 | height: 160, 71 | width: double.infinity, 72 | margin: EdgeInsets.only(top: 16, left: 16, right: 16), 73 | child: ClipRRect( 74 | borderRadius: BorderRadius.circular(12.0), 75 | child: Image.network( 76 | image, 77 | fit: BoxFit.cover, 78 | )), 79 | ), 80 | SizedBox( 81 | height: 12, 82 | ), 83 | Container( 84 | height: 70, 85 | margin: EdgeInsets.only(left: 16, right: 16), 86 | child: Column( 87 | crossAxisAlignment: CrossAxisAlignment.start, 88 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 89 | children: [ 90 | Text( 91 | title, 92 | maxLines: 3, 93 | overflow: TextOverflow.ellipsis, 94 | style: TextStyle( 95 | fontSize: 14, 96 | fontWeight: FontWeight.bold, 97 | color: HexColor('#4E3A55')), 98 | ), 99 | Padding( 100 | padding: const EdgeInsets.only(bottom: 12.0), 101 | child: Text( 102 | published, 103 | style: TextStyle( 104 | fontSize: 14, color: HexColor('#999CA0')), 105 | ), 106 | ) 107 | ], 108 | ), 109 | ) 110 | ], 111 | ))), 112 | ), 113 | ), 114 | ); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /lib/view/home.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:newsly/view/page/business/businessNews.dart'; 5 | import 'package:newsly/view/drawer.dart'; 6 | import 'package:newsly/view/page/general/generalNews.dart'; 7 | import 'package:newsly/view/page/health/healthNews.dart'; 8 | import 'package:newsly/view/page/sport/sportNews.dart'; 9 | import 'package:newsly/view/page/technology/technologyNews.dart'; 10 | 11 | class Home extends StatefulWidget { 12 | Home({Key? key}) : super(key: key); 13 | 14 | @override 15 | State createState() => _HomeState(); 16 | } 17 | 18 | class _HomeState extends State { 19 | @override 20 | Widget build(BuildContext context) { 21 | // NewsList news = NewsList(); 22 | // NewsHeadlines newsHeadlines = NewsHeadlines(); 23 | Widget _bagianTabBar = TabBar( 24 | isScrollable: true, 25 | unselectedLabelColor: Colors.blue, 26 | indicatorSize: TabBarIndicatorSize.tab, 27 | indicator: BoxDecoration( 28 | borderRadius: BorderRadius.circular(50), color: Colors.blue), 29 | tabs: [ 30 | Tab( 31 | child: Container( 32 | decoration: BoxDecoration( 33 | borderRadius: BorderRadius.circular(50), 34 | //border: Border.all(color: Colors.blue) 35 | ), 36 | child: Align( 37 | alignment: Alignment.center, 38 | child: Padding( 39 | padding: const EdgeInsets.only(left: 12, right: 12), 40 | child: Text("General"), 41 | ), 42 | ), 43 | ), 44 | ), 45 | Tab( 46 | child: Container( 47 | decoration: BoxDecoration( 48 | borderRadius: BorderRadius.circular(50), 49 | //border: Border.all(color: Colors.blue) 50 | ), 51 | child: Align( 52 | alignment: Alignment.center, 53 | child: Padding( 54 | padding: const EdgeInsets.only(left: 12, right: 12), 55 | child: Text("Technology"), 56 | ), 57 | ), 58 | ), 59 | ), 60 | Tab( 61 | child: Container( 62 | decoration: BoxDecoration( 63 | borderRadius: BorderRadius.circular(50), 64 | //border: Border.all(color: Colors.blue) 65 | ), 66 | child: Align( 67 | alignment: Alignment.center, 68 | child: Padding( 69 | padding: const EdgeInsets.only(left: 12, right: 12), 70 | child: Text("Business"), 71 | ), 72 | ), 73 | ), 74 | ), 75 | Tab( 76 | child: Container( 77 | decoration: BoxDecoration( 78 | borderRadius: BorderRadius.circular(50), 79 | //border: Border.all(color: Colors.blue) 80 | ), 81 | child: Align( 82 | alignment: Alignment.center, 83 | child: Padding( 84 | padding: const EdgeInsets.only(left: 12, right: 12), 85 | child: Text("Health"), 86 | ), 87 | ), 88 | ), 89 | ), 90 | Tab( 91 | child: Container( 92 | decoration: BoxDecoration( 93 | borderRadius: BorderRadius.circular(50), 94 | //border: Border.all(color: Colors.blue) 95 | ), 96 | child: Align( 97 | alignment: Alignment.center, 98 | child: Padding( 99 | padding: const EdgeInsets.only(left: 12, right: 12), 100 | child: Text("Sport"), 101 | ), 102 | ), 103 | ), 104 | ), 105 | ]); 106 | 107 | return DefaultTabController( 108 | length: 5, 109 | child: Scaffold( 110 | appBar: AppBar( 111 | title: Center( 112 | child: Text( 113 | 'Newsly', 114 | style: TextStyle( 115 | fontWeight: FontWeight.bold, color: Colors.blue[700]), 116 | )), 117 | backgroundColor: Colors.white, 118 | iconTheme: IconThemeData(color: Colors.black), 119 | elevation: 0, 120 | bottom: PreferredSize( 121 | preferredSize: new Size(200.0, 52), 122 | child: Container( 123 | margin: EdgeInsets.only(left: 16, right: 16), 124 | child: _bagianTabBar), 125 | ), 126 | actions: [ 127 | Container( 128 | margin: EdgeInsets.only(right: 0), 129 | child: IconButton( 130 | onPressed: () {}, 131 | icon: Image.asset('images/icon_user.png')), 132 | ) 133 | ], 134 | ), 135 | backgroundColor: Colors.white, 136 | drawer: DrawerMenu(), 137 | body: TabBarView( 138 | children: [ 139 | GeneralNews(), 140 | TechnologyNews(), 141 | BusinessNews(), 142 | HealthNews(), 143 | SportNews() 144 | ], 145 | ))); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /lib/view/widget/dialog_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:newsly/view/page/articles/articles_page.dart'; 3 | import 'package:newsly/view/page/articles/formUpdateArticle.dart'; 4 | import 'package:newsly/viewmodel/service/firestore_service.dart'; 5 | 6 | class DetailDialog extends StatelessWidget { 7 | String? image; 8 | String? title; 9 | String? author; 10 | String? published; 11 | String? description; 12 | String? id; 13 | String? urlArtikel; 14 | 15 | DetailDialog( 16 | {Key? key, 17 | this.image, 18 | this.title, 19 | this.author, 20 | this.published, 21 | this.description, 22 | this.id, 23 | this.urlArtikel}) 24 | : super(key: key); 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return SimpleDialog( 29 | elevation: 4, 30 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)), 31 | children: [ 32 | Container( 33 | margin: EdgeInsets.only(right: 16, left: 16, top: 6), 34 | child: Column( 35 | crossAxisAlignment: CrossAxisAlignment.start, 36 | children: [ 37 | Container( 38 | height: 180, 39 | width: double.infinity, 40 | child: ClipRRect( 41 | borderRadius: BorderRadius.circular(8.0), 42 | child: Image.network( 43 | image!, 44 | fit: BoxFit.cover, 45 | ), 46 | ), 47 | ), 48 | SizedBox( 49 | height: 16, 50 | ), 51 | Text( 52 | title!, 53 | style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), 54 | ), 55 | SizedBox( 56 | height: 8.0, 57 | ), 58 | Row( 59 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 60 | children: [ 61 | Row( 62 | children: [ 63 | Image.asset( 64 | 'images/icon_user.png', 65 | height: 24, 66 | width: 24, 67 | ), 68 | SizedBox( 69 | width: 12, 70 | ), 71 | Text( 72 | author!, 73 | style: TextStyle(color: Colors.grey), 74 | ) 75 | ], 76 | ), 77 | Text(published!, style: TextStyle(color: Colors.grey)), 78 | ], 79 | ), 80 | SizedBox( 81 | height: 16, 82 | ), 83 | Text(description!), 84 | SizedBox( 85 | height: 16, 86 | ), 87 | Row( 88 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 89 | children: [ 90 | Row( 91 | children: [ 92 | TextButton( 93 | onPressed: () { 94 | Navigator.pushReplacement( 95 | context, 96 | MaterialPageRoute( 97 | builder: (_) => FormUpdateArticle( 98 | id: id!, 99 | author: author!, 100 | date: published!, 101 | deskripsi: description!, 102 | image: image!, 103 | title: title!, 104 | urlArtikel: urlArtikel!))); 105 | }, 106 | child: Text( 107 | "Update", 108 | style: TextStyle(color: Colors.green), 109 | )), 110 | SizedBox( 111 | width: 4.0, 112 | ), 113 | TextButton( 114 | onPressed: () { 115 | Navigator.of(context).pop(); 116 | FirestoreService.deleteItem(id: id!) 117 | .then((value) => showDialog( 118 | context: context, 119 | builder: (context) { 120 | return AlertDialog( 121 | title: Text("Data Berhasil Dihapus"), 122 | actions: [ 123 | TextButton( 124 | onPressed: () { 125 | Navigator.pushReplacement( 126 | context, 127 | MaterialPageRoute( 128 | builder: (context) => 129 | ArticlesPage())); 130 | }, 131 | child: Text("OK")) 132 | ], 133 | ); 134 | })); 135 | }, 136 | child: Text( 137 | "Delete", 138 | style: TextStyle(color: Colors.red), 139 | )), 140 | ], 141 | ), 142 | TextButton( 143 | onPressed: () {}, 144 | child: Text( 145 | "Close", 146 | style: TextStyle(color: Colors.grey), 147 | )), 148 | ], 149 | ) 150 | ], 151 | ), 152 | ), 153 | ]); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /lib/view/widget/newsList.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hexcolor/hexcolor.dart'; 3 | import 'package:newsly/model/news.dart'; 4 | import 'package:newsly/view/detailNews.dart'; 5 | 6 | class BreakNewsList extends StatelessWidget { 7 | const BreakNewsList({ Key? key, required this.news }) : super(key: key); 8 | 9 | final List news; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return ListView.builder( 14 | itemCount: news.length, 15 | shrinkWrap: true, 16 | scrollDirection: Axis.horizontal, 17 | itemBuilder: (context, index){ 18 | return GestureDetector( 19 | onTap: () { 20 | Navigator.push( 21 | context, 22 | MaterialPageRoute( 23 | builder: (contex) => DetailNews( 24 | author: news[index].author, 25 | title: news[index].title, 26 | image: news[index].image, 27 | published: news[index].published, 28 | content: news[index].content, 29 | url: news[index].url, 30 | source: news[index].source, 31 | ))); 32 | }, 33 | child: Container( 34 | width: 304, 35 | child: Padding( 36 | padding: const EdgeInsets.only(left: 16), 37 | child: Card( 38 | shape: RoundedRectangleBorder( 39 | borderRadius: BorderRadius.circular(20), 40 | ), 41 | child: Container( 42 | child: Column( 43 | crossAxisAlignment: CrossAxisAlignment.start, 44 | children: [ 45 | Container( 46 | height: 144, 47 | margin: 48 | EdgeInsets.only(top: 16, left: 16, right: 16), 49 | child: ClipRRect( 50 | borderRadius: BorderRadius.circular(12.0), 51 | child: Image.network( 52 | news[index].image, 53 | fit: BoxFit.cover, 54 | )), 55 | ), 56 | SizedBox( 57 | height: 12, 58 | ), 59 | Container( 60 | height: 70, 61 | margin: EdgeInsets.only(left: 16, right: 16), 62 | child: Column( 63 | crossAxisAlignment: CrossAxisAlignment.start, 64 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 65 | children: [ 66 | Text( 67 | news[index].title, 68 | maxLines: 3, 69 | overflow: TextOverflow.ellipsis, 70 | style: TextStyle( 71 | fontSize: 14, 72 | fontWeight: FontWeight.bold, 73 | color: HexColor('#4E3A55')), 74 | ), 75 | 76 | Text( 77 | news[index].published, 78 | style: TextStyle( 79 | fontSize: 14, color: HexColor('#999CA0')), 80 | ) 81 | ], 82 | ), 83 | ) 84 | ], 85 | ))), 86 | ), 87 | ), 88 | ); 89 | }, 90 | ); 91 | } 92 | } 93 | 94 | class TopHeadlinesList extends StatelessWidget { 95 | const TopHeadlinesList({ Key? key, required this.news }) : super(key: key); 96 | 97 | final List news; 98 | 99 | 100 | @override 101 | Widget build(BuildContext context) { 102 | 103 | return Flexible( 104 | child: ListView.builder( 105 | physics: NeverScrollableScrollPhysics(), 106 | shrinkWrap: true, 107 | itemCount: news.length, 108 | reverse: true, 109 | itemBuilder: (context, index) { 110 | return GestureDetector( 111 | onTap: () { 112 | Navigator.push( 113 | context, 114 | MaterialPageRoute( 115 | builder: (contex) => DetailNews( 116 | author: news[index].author, 117 | title: news[index].title, 118 | image: news[index].image, 119 | published: news[index].published, 120 | content: news[index].content, 121 | url: news[index].url, 122 | source: news[index].source, 123 | ))); 124 | }, 125 | child: Container( 126 | margin: EdgeInsets.only(left: 16, right: 16, bottom: 12), 127 | height: 120, 128 | child: Card( 129 | child: Row( 130 | children: [ 131 | Container( 132 | width: 73, 133 | height: 77, 134 | margin: 135 | EdgeInsets.only(left: 16, top: 16, bottom: 16), 136 | child: ClipRRect( 137 | borderRadius: BorderRadius.circular(4.0), 138 | child: Image.network( 139 | news[index].image, 140 | fit: BoxFit.cover, 141 | ), 142 | ), 143 | ), 144 | SizedBox( 145 | width: 16, 146 | ), 147 | Container( 148 | margin: EdgeInsets.only(top: 16, bottom: 16), 149 | width: 206, 150 | child: Column( 151 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 152 | crossAxisAlignment: CrossAxisAlignment.start, 153 | children: [ 154 | Text( 155 | news[index].title, 156 | maxLines: 3, 157 | overflow: TextOverflow.ellipsis, 158 | style: TextStyle( 159 | fontWeight: FontWeight.bold, 160 | color: HexColor('#4E3A55')), 161 | ), 162 | 163 | Text( 164 | news[index].content, 165 | maxLines: 2, 166 | overflow: TextOverflow.ellipsis, 167 | style: TextStyle( 168 | color: HexColor('#999CA0'), 169 | fontSize: 12 170 | ), 171 | ) 172 | ], 173 | )) 174 | ], 175 | ), 176 | ), 177 | ), 178 | ); 179 | }), 180 | ); 181 | } 182 | } -------------------------------------------------------------------------------- /lib/view/page/articles/articles_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_firestore/cloud_firestore.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:newsly/view/drawer.dart'; 4 | import 'package:newsly/view/widget/card_widget.dart'; 5 | import 'package:shimmer/shimmer.dart'; 6 | 7 | class ArticlesPage extends StatelessWidget { 8 | ArticlesPage({ 9 | Key? key, 10 | }) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | FirebaseFirestore _firestore = FirebaseFirestore.instance; 15 | CollectionReference _articles = _firestore.collection('articles'); 16 | 17 | return Scaffold( 18 | appBar: AppBar( 19 | title: Text( 20 | "Articles", 21 | style: 22 | TextStyle(color: Colors.blue[700], fontWeight: FontWeight.bold), 23 | ), 24 | centerTitle: true, 25 | elevation: 0, 26 | iconTheme: IconThemeData(color: Colors.black), 27 | backgroundColor: Colors.white, 28 | actions: [ 29 | Container( 30 | margin: EdgeInsets.only(right: 0), 31 | child: IconButton( 32 | onPressed: () {}, icon: Image.asset('images/icon_user.png')), 33 | ) 34 | ], 35 | ), 36 | backgroundColor: Colors.white, 37 | body: Container( 38 | child: ListView( 39 | children: [ 40 | StreamBuilder( 41 | stream: _articles.snapshots(), 42 | builder: (_, snapshot) { 43 | if (snapshot.hasData) { 44 | return Column( 45 | children: snapshot.data!.docs 46 | .map((DocumentSnapshot document) { 47 | Map data = 48 | document.data() as Map; 49 | return ItemCard( 50 | author: data['author'], 51 | title: data['title'], 52 | published: data['published'], 53 | description: data['description'], 54 | image: data['image'], 55 | urlArtikel: data['url'], 56 | id: document.id, 57 | ); 58 | }).toList()); 59 | } else { 60 | return Shimmer.fromColors( 61 | baseColor: Colors.grey, 62 | highlightColor: Colors.white70, 63 | child: Column( 64 | children: [ 65 | Container( 66 | width: double.infinity, 67 | child: Padding( 68 | padding: 69 | const EdgeInsets.only(left: 8.0, right: 8.0), 70 | child: Card( 71 | elevation: 1, 72 | shadowColor: Colors.blue, 73 | shape: RoundedRectangleBorder( 74 | borderRadius: BorderRadius.circular(8.0), 75 | ), 76 | child: Container( 77 | child: Column( 78 | crossAxisAlignment: 79 | CrossAxisAlignment.start, 80 | children: [ 81 | Container( 82 | height: 160, 83 | width: double.infinity, 84 | margin: EdgeInsets.only( 85 | top: 16, left: 16, right: 16), 86 | ), 87 | SizedBox( 88 | height: 12, 89 | ), 90 | Container( 91 | height: 70, 92 | margin: EdgeInsets.only( 93 | left: 16, right: 16), 94 | ) 95 | ], 96 | ))), 97 | ), 98 | ), 99 | Container( 100 | width: double.infinity, 101 | child: Padding( 102 | padding: 103 | const EdgeInsets.only(left: 8.0, right: 8.0), 104 | child: Card( 105 | elevation: 1, 106 | shadowColor: Colors.blue, 107 | shape: RoundedRectangleBorder( 108 | borderRadius: BorderRadius.circular(8.0), 109 | ), 110 | child: Container( 111 | child: Column( 112 | crossAxisAlignment: 113 | CrossAxisAlignment.start, 114 | children: [ 115 | Container( 116 | height: 160, 117 | width: double.infinity, 118 | margin: EdgeInsets.only( 119 | top: 16, left: 16, right: 16), 120 | ), 121 | SizedBox( 122 | height: 12, 123 | ), 124 | Container( 125 | height: 70, 126 | margin: EdgeInsets.only( 127 | left: 16, right: 16), 128 | ) 129 | ], 130 | ))), 131 | ), 132 | ), 133 | Container( 134 | width: double.infinity, 135 | child: Padding( 136 | padding: 137 | const EdgeInsets.only(left: 8.0, right: 8.0), 138 | child: Card( 139 | elevation: 1, 140 | shadowColor: Colors.blue, 141 | shape: RoundedRectangleBorder( 142 | borderRadius: BorderRadius.circular(8.0), 143 | ), 144 | child: Container( 145 | child: Column( 146 | crossAxisAlignment: 147 | CrossAxisAlignment.start, 148 | children: [ 149 | Container( 150 | height: 160, 151 | width: double.infinity, 152 | margin: EdgeInsets.only( 153 | top: 16, left: 16, right: 16), 154 | ), 155 | SizedBox( 156 | height: 12, 157 | ), 158 | Container( 159 | height: 70, 160 | margin: EdgeInsets.only( 161 | left: 16, right: 16), 162 | ) 163 | ], 164 | ))), 165 | ), 166 | ) 167 | ] 168 | )); 169 | } 170 | }) 171 | ], 172 | ), 173 | ), 174 | drawer: DrawerMenu(), 175 | ); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /lib/view/page/articles/formAddArticle.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:cloud_firestore/cloud_firestore.dart'; 4 | import 'package:firebase_storage/firebase_storage.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:hexcolor/hexcolor.dart'; 7 | import 'package:image_picker/image_picker.dart'; 8 | import 'package:date_field/date_field.dart'; 9 | import 'package:intl/intl.dart'; 10 | import 'package:newsly/viewmodel/service/firestore_service.dart'; 11 | 12 | class FormAddArticle extends StatefulWidget { 13 | FormAddArticle({Key? key}) : super(key: key); 14 | 15 | @override 16 | State createState() => _FormAddArticleState(); 17 | } 18 | 19 | class _FormAddArticleState extends State { 20 | TextEditingController _controllerTitle = new TextEditingController(); 21 | TextEditingController _controllerAuthor = new TextEditingController(); 22 | TextEditingController _controllerUrl = new TextEditingController(); 23 | TextEditingController _controllerDeskripsi = new TextEditingController(); 24 | 25 | String _title = ''; 26 | String _date = ''; 27 | String _author = ''; 28 | String _urlArtikel = ''; 29 | String _deskripsi = ''; 30 | 31 | XFile? image; 32 | String? namaGamber; 33 | final ImagePicker _picker = ImagePicker(); 34 | 35 | Future chooseImage() async { 36 | XFile? selectedImage = await _picker.pickImage(source: ImageSource.gallery); 37 | setState(() { 38 | image = selectedImage; 39 | namaGamber = image!.name; 40 | }); 41 | } 42 | 43 | Widget showImage() { 44 | return image == null 45 | ? Container( 46 | width: double.infinity, 47 | height: 150, 48 | decoration: BoxDecoration( 49 | color: HexColor("#F5F5F5"), 50 | borderRadius: BorderRadius.circular(8.0)), 51 | child: Center( 52 | child: Icon( 53 | Icons.add_photo_alternate_outlined, 54 | size: 40, 55 | color: Colors.grey, 56 | ))) 57 | : uploadArea(); 58 | } 59 | 60 | Future uploadItemImage() async { 61 | Reference ref = FirebaseStorage.instance.ref().child(namaGamber!); 62 | 63 | UploadTask uploadTask = ref.putFile(File(image!.path)); 64 | 65 | var downUrl = await uploadTask.then((res) => res.ref.getDownloadURL()); 66 | var url = downUrl.toString(); 67 | 68 | print("Download URL : " + url); 69 | 70 | tambahItem(url); 71 | 72 | return url != null ? "upload sukses" : "Upload gagal"; 73 | } 74 | 75 | @override 76 | Widget build(BuildContext context) { 77 | return Scaffold( 78 | appBar: AppBar( 79 | title: Text( 80 | "Add Article", 81 | style: TextStyle(color: Colors.blue, fontWeight: FontWeight.bold), 82 | ), 83 | centerTitle: true, 84 | backgroundColor: Colors.white, 85 | iconTheme: IconThemeData(color: Colors.black), 86 | elevation: 0, 87 | ), 88 | backgroundColor: Colors.white, 89 | body: Container( 90 | padding: EdgeInsets.all(20.0), 91 | child: ListView( 92 | children: [ 93 | GestureDetector( 94 | onTap: () { 95 | chooseImage(); 96 | }, 97 | child: showImage(), 98 | ), 99 | SizedBox( 100 | height: 20, 101 | ), 102 | TextField( 103 | controller: _controllerTitle, 104 | decoration: InputDecoration( 105 | hintText: "Judul Artikel", 106 | labelText: "Judul Artikel", 107 | border: OutlineInputBorder( 108 | borderRadius: BorderRadius.circular(8.0))), 109 | ), 110 | SizedBox( 111 | height: 16, 112 | ), 113 | TextField( 114 | controller: _controllerAuthor, 115 | decoration: InputDecoration( 116 | hintText: "Author", 117 | labelText: "Author", 118 | border: OutlineInputBorder( 119 | borderRadius: BorderRadius.circular(8.0))), 120 | ), 121 | SizedBox( 122 | height: 16, 123 | ), 124 | DateTimeFormField( 125 | decoration: InputDecoration( 126 | hintText: "Date", 127 | labelText: "Date", 128 | prefixIcon: Icon(Icons.date_range_outlined), 129 | border: OutlineInputBorder( 130 | borderRadius: BorderRadius.circular(8.0))), 131 | mode: DateTimeFieldPickerMode.date, 132 | dateFormat: DateFormat("yyyy-MM-dd"), 133 | onDateSelected: (DateTime value) { 134 | setState(() { 135 | String formatDate = DateFormat("yyyy-MM-dd").format(value); 136 | _date = formatDate; 137 | }); 138 | }, 139 | ), 140 | SizedBox( 141 | height: 16, 142 | ), 143 | TextField( 144 | controller: _controllerUrl, 145 | decoration: InputDecoration( 146 | hintText: "Url Artikel", 147 | labelText: "Url Artikel", 148 | border: OutlineInputBorder( 149 | borderRadius: BorderRadius.circular(8.0))), 150 | ), 151 | SizedBox( 152 | height: 16, 153 | ), 154 | TextField( 155 | maxLines: 8, 156 | controller: _controllerDeskripsi, 157 | decoration: InputDecoration( 158 | hintText: "Deskripsi", 159 | labelText: "Deskripsi", 160 | border: OutlineInputBorder( 161 | borderRadius: BorderRadius.circular(8.0))), 162 | ), 163 | SizedBox( 164 | height: 16, 165 | ), 166 | MaterialButton( 167 | onPressed: () { 168 | _title = _controllerTitle.text; 169 | _author = _controllerAuthor.text; 170 | _urlArtikel = _controllerUrl.text; 171 | _deskripsi = _controllerDeskripsi.text; 172 | 173 | uploadItemImage(); 174 | 175 | setState(() { 176 | _controllerTitle.clear(); 177 | _controllerAuthor.clear(); 178 | _controllerDeskripsi.clear(); 179 | _controllerUrl.clear(); 180 | image = null; 181 | }); 182 | }, 183 | color: Colors.blue, 184 | textColor: Colors.white, 185 | child: Text("Submit"), 186 | minWidth: double.infinity, 187 | padding: EdgeInsets.only(top: 14, bottom: 14), 188 | shape: RoundedRectangleBorder( 189 | borderRadius: BorderRadius.circular(8)), 190 | ) 191 | ], 192 | )), 193 | ); 194 | } 195 | 196 | Future tambahItem(String url) { 197 | FirebaseFirestore _firestore = FirebaseFirestore.instance; 198 | CollectionReference _articles = _firestore.collection('articles'); 199 | 200 | return FirestoreService.addItem( 201 | title: _title, 202 | author: _author, 203 | published: _date, 204 | urlArticle: _urlArtikel, 205 | description: _deskripsi, 206 | image: url, 207 | id: _articles.doc().id) 208 | .then((value) => showDialog( 209 | context: context, 210 | builder: (context) { 211 | return AlertDialog( 212 | title: Text("Data Berhasil Ditambahkan"), 213 | actions: [ 214 | TextButton( 215 | onPressed: () { 216 | Navigator.of(context).pop(); 217 | }, 218 | child: Text("OK")) 219 | ], 220 | ); 221 | })); 222 | } 223 | 224 | Widget uploadArea() { 225 | return Container( 226 | height: 150, 227 | child: ClipRRect( 228 | child: Image.file( 229 | File(image!.path), 230 | fit: BoxFit.cover, 231 | ), 232 | borderRadius: BorderRadius.circular(8.0), 233 | ), 234 | decoration: BoxDecoration(borderRadius: BorderRadius.circular(8.0)), 235 | ); 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /lib/view/page/articles/formUpdateArticle.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:date_field/date_field.dart'; 4 | import 'package:firebase_storage/firebase_storage.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:image_picker/image_picker.dart'; 7 | import 'package:newsly/view/page/articles/articles_page.dart'; 8 | import 'package:newsly/viewmodel/service/firestore_service.dart'; 9 | import 'package:intl/intl.dart'; 10 | 11 | class FormUpdateArticle extends StatefulWidget { 12 | String id; 13 | String title = ''; 14 | String date = ''; 15 | String author = ''; 16 | String urlArtikel = ''; 17 | String deskripsi = ''; 18 | String image = ''; 19 | 20 | FormUpdateArticle( 21 | {Key? key, 22 | required this.id, 23 | required this.author, 24 | required this.date, 25 | required this.deskripsi, 26 | required this.image, 27 | required this.title, 28 | required this.urlArtikel}) 29 | : super(key: key); 30 | 31 | @override 32 | _FormUpdateArticleState createState() => _FormUpdateArticleState( 33 | id: id, 34 | date: date, 35 | author: author, 36 | gambar: image, 37 | deskripsi: deskripsi, 38 | title: title, 39 | urlArtikel: urlArtikel); 40 | } 41 | 42 | class _FormUpdateArticleState extends State { 43 | String title; 44 | String date; 45 | String author; 46 | String urlArtikel; 47 | String deskripsi; 48 | String id; 49 | String gambar; 50 | 51 | _FormUpdateArticleState( 52 | {required this.id, 53 | required this.date, 54 | required this.author, 55 | required this.gambar, 56 | required this.deskripsi, 57 | required this.title, 58 | required this.urlArtikel}); 59 | 60 | DateTime? tgl; 61 | TextEditingController? _controllerTitle; 62 | TextEditingController? _controllerAuthor; 63 | TextEditingController? _controllerUrl; 64 | TextEditingController? _controllerDeskripsi; 65 | 66 | void initState() { 67 | super.initState(); 68 | _controllerTitle = new TextEditingController()..text = title; 69 | _controllerAuthor = new TextEditingController()..text = author; 70 | _controllerDeskripsi = new TextEditingController()..text = deskripsi; 71 | _controllerUrl = new TextEditingController()..text = urlArtikel; 72 | tgl = DateTime.parse(date); 73 | } 74 | 75 | XFile? image; 76 | String? namaGambar; 77 | final ImagePicker _picker = ImagePicker(); 78 | 79 | Future chooseImage() async { 80 | XFile? selectedImage = await _picker.pickImage(source: ImageSource.gallery); 81 | setState(() { 82 | image = selectedImage; 83 | namaGambar = image!.name; 84 | }); 85 | } 86 | 87 | Future uploadItemImage() async { 88 | var url; 89 | if (image == null) { 90 | url = gambar; 91 | } else { 92 | Reference ref = FirebaseStorage.instance.ref().child(namaGambar!); 93 | 94 | UploadTask uploadTask = ref.putFile(File(image!.path)); 95 | 96 | var downUrl = await uploadTask.then((res) => res.ref.getDownloadURL()); 97 | url = downUrl.toString(); 98 | } 99 | print("Download URL : " + url); 100 | 101 | updateItem(url); 102 | 103 | return url != null ? "upload sukses" : "Upload gagal"; 104 | } 105 | 106 | Widget showImage() { 107 | return image == null ? uploadAreaID() : uploadArea(); 108 | } 109 | 110 | @override 111 | Widget build(BuildContext context) { 112 | return Scaffold( 113 | appBar: AppBar( 114 | title: Text( 115 | "Update Article", 116 | style: TextStyle(color: Colors.blue, fontWeight: FontWeight.bold), 117 | ), 118 | centerTitle: true, 119 | backgroundColor: Colors.white, 120 | iconTheme: IconThemeData(color: Colors.black), 121 | elevation: 0, 122 | ), 123 | backgroundColor: Colors.white, 124 | body: Container( 125 | padding: EdgeInsets.all(20.0), 126 | child: ListView( 127 | children: [ 128 | GestureDetector( 129 | onTap: () { 130 | chooseImage(); 131 | }, 132 | child: showImage(), 133 | ), 134 | SizedBox( 135 | height: 20, 136 | ), 137 | TextField( 138 | controller: _controllerTitle, 139 | decoration: InputDecoration( 140 | hintText: "Judul Artikel", 141 | labelText: "Judul Artikel", 142 | border: OutlineInputBorder( 143 | borderRadius: BorderRadius.circular(8.0))), 144 | ), 145 | SizedBox( 146 | height: 16, 147 | ), 148 | TextField( 149 | controller: _controllerAuthor, 150 | decoration: InputDecoration( 151 | hintText: "Author", 152 | labelText: "Author", 153 | border: OutlineInputBorder( 154 | borderRadius: BorderRadius.circular(8.0))), 155 | ), 156 | SizedBox( 157 | height: 16, 158 | ), 159 | DateTimeFormField( 160 | decoration: InputDecoration( 161 | hintText: "Date", 162 | labelText: "Date", 163 | prefixIcon: Icon(Icons.date_range_outlined), 164 | border: OutlineInputBorder( 165 | borderRadius: BorderRadius.circular(8.0))), 166 | mode: DateTimeFieldPickerMode.date, 167 | dateFormat: DateFormat("yyyy-MM-dd"), 168 | initialValue: tgl, 169 | onDateSelected: (DateTime value) { 170 | setState(() { 171 | String formatDate = DateFormat("yyyy-MM-dd").format(value); 172 | date = formatDate; 173 | }); 174 | }, 175 | ), 176 | SizedBox( 177 | height: 16, 178 | ), 179 | TextField( 180 | controller: _controllerUrl, 181 | decoration: InputDecoration( 182 | hintText: "Url Artikel", 183 | labelText: "Url Artikel", 184 | border: OutlineInputBorder( 185 | borderRadius: BorderRadius.circular(8.0))), 186 | ), 187 | SizedBox( 188 | height: 16 189 | ), 190 | TextField( 191 | maxLines: 8, 192 | controller: _controllerDeskripsi, 193 | decoration: InputDecoration( 194 | hintText: "Deskripsi", 195 | labelText: "Deskripsi", 196 | border: OutlineInputBorder( 197 | borderRadius: BorderRadius.circular(8.0))), 198 | ), 199 | SizedBox( 200 | height: 16, 201 | ), 202 | MaterialButton( 203 | onPressed: () { 204 | title = _controllerTitle!.text; 205 | author = _controllerAuthor!.text; 206 | urlArtikel = _controllerUrl!.text; 207 | deskripsi = _controllerDeskripsi!.text; 208 | 209 | Navigator.pushReplacement(context, 210 | MaterialPageRoute(builder: (context) => ArticlesPage())); 211 | 212 | uploadItemImage().then((value) => showDialog( 213 | context: context, 214 | builder: (context) { 215 | return AlertDialog( 216 | title: Text("Data Berhasil Diupdate"), 217 | actions: [ 218 | TextButton( 219 | onPressed: () { 220 | Navigator.pop(context, 'OK'); 221 | }, 222 | child: Text("OK")) 223 | ], 224 | ); 225 | })); 226 | 227 | 228 | setState(() { 229 | _controllerTitle!.clear(); 230 | _controllerAuthor!.clear(); 231 | _controllerDeskripsi!.clear(); 232 | _controllerUrl!.clear(); 233 | image = null; 234 | }); 235 | }, 236 | color: Colors.blue, 237 | textColor: Colors.white, 238 | child: Text("Update"), 239 | minWidth: double.infinity, 240 | padding: EdgeInsets.only(top: 14, bottom: 14), 241 | shape: RoundedRectangleBorder( 242 | borderRadius: BorderRadius.circular(8)), 243 | ) 244 | ], 245 | )), 246 | ); 247 | } 248 | 249 | Future updateItem(String url) { 250 | return FirestoreService.updateItem( 251 | title: title, 252 | author: author, 253 | published: date, 254 | urlArticle: urlArtikel, 255 | description: deskripsi, 256 | image: url, 257 | id: id); 258 | } 259 | 260 | Widget uploadArea() { 261 | return Container( 262 | height: 150, 263 | child: ClipRRect( 264 | child: Image.file( 265 | File(image!.path), 266 | fit: BoxFit.cover, 267 | ), 268 | borderRadius: BorderRadius.circular(8.0), 269 | ), 270 | decoration: BoxDecoration(borderRadius: BorderRadius.circular(8.0)), 271 | ); 272 | } 273 | 274 | Widget uploadAreaID() { 275 | return Container( 276 | height: 150, 277 | child: ClipRRect( 278 | child: Image.network( 279 | gambar, 280 | fit: BoxFit.cover, 281 | ), 282 | borderRadius: BorderRadius.circular(8.0), 283 | ), 284 | decoration: BoxDecoration(borderRadius: BorderRadius.circular(8.0)), 285 | ); 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | animated_splash_screen: 5 | dependency: "direct main" 6 | description: 7 | name: animated_splash_screen 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "1.1.0" 11 | async: 12 | dependency: transitive 13 | description: 14 | name: async 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.8.1" 18 | boolean_selector: 19 | dependency: transitive 20 | description: 21 | name: boolean_selector 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "2.1.0" 25 | characters: 26 | dependency: transitive 27 | description: 28 | name: characters 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.1.0" 32 | charcode: 33 | dependency: transitive 34 | description: 35 | name: charcode 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.3.1" 39 | clock: 40 | dependency: transitive 41 | description: 42 | name: clock 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.1.0" 46 | cloud_firestore: 47 | dependency: "direct main" 48 | description: 49 | name: cloud_firestore 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "3.1.0" 53 | cloud_firestore_platform_interface: 54 | dependency: transitive 55 | description: 56 | name: cloud_firestore_platform_interface 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "5.4.5" 60 | cloud_firestore_web: 61 | dependency: transitive 62 | description: 63 | name: cloud_firestore_web 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "2.5.0" 67 | collection: 68 | dependency: transitive 69 | description: 70 | name: collection 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "1.15.0" 74 | cross_file: 75 | dependency: transitive 76 | description: 77 | name: cross_file 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "0.3.2" 81 | cupertino_icons: 82 | dependency: "direct main" 83 | description: 84 | name: cupertino_icons 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "1.0.4" 88 | date_field: 89 | dependency: "direct main" 90 | description: 91 | name: date_field 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "2.1.2" 95 | fake_async: 96 | dependency: transitive 97 | description: 98 | name: fake_async 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "1.2.0" 102 | firebase_core: 103 | dependency: "direct main" 104 | description: 105 | name: firebase_core 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "1.10.0" 109 | firebase_core_platform_interface: 110 | dependency: transitive 111 | description: 112 | name: firebase_core_platform_interface 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "4.1.0" 116 | firebase_core_web: 117 | dependency: transitive 118 | description: 119 | name: firebase_core_web 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "1.2.0" 123 | firebase_storage: 124 | dependency: "direct main" 125 | description: 126 | name: firebase_storage 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "10.1.0" 130 | firebase_storage_platform_interface: 131 | dependency: transitive 132 | description: 133 | name: firebase_storage_platform_interface 134 | url: "https://pub.dartlang.org" 135 | source: hosted 136 | version: "4.0.6" 137 | firebase_storage_web: 138 | dependency: transitive 139 | description: 140 | name: firebase_storage_web 141 | url: "https://pub.dartlang.org" 142 | source: hosted 143 | version: "3.1.0" 144 | flutter: 145 | dependency: "direct main" 146 | description: flutter 147 | source: sdk 148 | version: "0.0.0" 149 | flutter_plugin_android_lifecycle: 150 | dependency: transitive 151 | description: 152 | name: flutter_plugin_android_lifecycle 153 | url: "https://pub.dartlang.org" 154 | source: hosted 155 | version: "2.0.4" 156 | flutter_svg: 157 | dependency: "direct main" 158 | description: 159 | name: flutter_svg 160 | url: "https://pub.dartlang.org" 161 | source: hosted 162 | version: "0.22.0" 163 | flutter_test: 164 | dependency: "direct dev" 165 | description: flutter 166 | source: sdk 167 | version: "0.0.0" 168 | flutter_web_plugins: 169 | dependency: transitive 170 | description: flutter 171 | source: sdk 172 | version: "0.0.0" 173 | hexcolor: 174 | dependency: "direct main" 175 | description: 176 | name: hexcolor 177 | url: "https://pub.dartlang.org" 178 | source: hosted 179 | version: "2.0.5" 180 | http: 181 | dependency: "direct main" 182 | description: 183 | name: http 184 | url: "https://pub.dartlang.org" 185 | source: hosted 186 | version: "0.13.3" 187 | http_parser: 188 | dependency: transitive 189 | description: 190 | name: http_parser 191 | url: "https://pub.dartlang.org" 192 | source: hosted 193 | version: "4.0.0" 194 | image_picker: 195 | dependency: "direct main" 196 | description: 197 | name: image_picker 198 | url: "https://pub.dartlang.org" 199 | source: hosted 200 | version: "0.8.4+4" 201 | image_picker_for_web: 202 | dependency: transitive 203 | description: 204 | name: image_picker_for_web 205 | url: "https://pub.dartlang.org" 206 | source: hosted 207 | version: "2.1.4" 208 | image_picker_platform_interface: 209 | dependency: transitive 210 | description: 211 | name: image_picker_platform_interface 212 | url: "https://pub.dartlang.org" 213 | source: hosted 214 | version: "2.4.1" 215 | intl: 216 | dependency: transitive 217 | description: 218 | name: intl 219 | url: "https://pub.dartlang.org" 220 | source: hosted 221 | version: "0.17.0" 222 | js: 223 | dependency: transitive 224 | description: 225 | name: js 226 | url: "https://pub.dartlang.org" 227 | source: hosted 228 | version: "0.6.3" 229 | matcher: 230 | dependency: transitive 231 | description: 232 | name: matcher 233 | url: "https://pub.dartlang.org" 234 | source: hosted 235 | version: "0.12.10" 236 | meta: 237 | dependency: transitive 238 | description: 239 | name: meta 240 | url: "https://pub.dartlang.org" 241 | source: hosted 242 | version: "1.7.0" 243 | page_transition: 244 | dependency: transitive 245 | description: 246 | name: page_transition 247 | url: "https://pub.dartlang.org" 248 | source: hosted 249 | version: "2.0.1-nullsafety.0" 250 | path: 251 | dependency: transitive 252 | description: 253 | name: path 254 | url: "https://pub.dartlang.org" 255 | source: hosted 256 | version: "1.8.0" 257 | path_drawing: 258 | dependency: transitive 259 | description: 260 | name: path_drawing 261 | url: "https://pub.dartlang.org" 262 | source: hosted 263 | version: "0.5.1+1" 264 | path_parsing: 265 | dependency: transitive 266 | description: 267 | name: path_parsing 268 | url: "https://pub.dartlang.org" 269 | source: hosted 270 | version: "0.2.1" 271 | pedantic: 272 | dependency: transitive 273 | description: 274 | name: pedantic 275 | url: "https://pub.dartlang.org" 276 | source: hosted 277 | version: "1.11.1" 278 | petitparser: 279 | dependency: transitive 280 | description: 281 | name: petitparser 282 | url: "https://pub.dartlang.org" 283 | source: hosted 284 | version: "4.1.0" 285 | plugin_platform_interface: 286 | dependency: transitive 287 | description: 288 | name: plugin_platform_interface 289 | url: "https://pub.dartlang.org" 290 | source: hosted 291 | version: "2.0.2" 292 | shimmer: 293 | dependency: "direct main" 294 | description: 295 | name: shimmer 296 | url: "https://pub.dartlang.org" 297 | source: hosted 298 | version: "2.0.0" 299 | sky_engine: 300 | dependency: transitive 301 | description: flutter 302 | source: sdk 303 | version: "0.0.99" 304 | source_span: 305 | dependency: transitive 306 | description: 307 | name: source_span 308 | url: "https://pub.dartlang.org" 309 | source: hosted 310 | version: "1.8.1" 311 | stack_trace: 312 | dependency: transitive 313 | description: 314 | name: stack_trace 315 | url: "https://pub.dartlang.org" 316 | source: hosted 317 | version: "1.10.0" 318 | stream_channel: 319 | dependency: transitive 320 | description: 321 | name: stream_channel 322 | url: "https://pub.dartlang.org" 323 | source: hosted 324 | version: "2.1.0" 325 | string_scanner: 326 | dependency: transitive 327 | description: 328 | name: string_scanner 329 | url: "https://pub.dartlang.org" 330 | source: hosted 331 | version: "1.1.0" 332 | term_glyph: 333 | dependency: transitive 334 | description: 335 | name: term_glyph 336 | url: "https://pub.dartlang.org" 337 | source: hosted 338 | version: "1.2.0" 339 | test_api: 340 | dependency: transitive 341 | description: 342 | name: test_api 343 | url: "https://pub.dartlang.org" 344 | source: hosted 345 | version: "0.4.2" 346 | typed_data: 347 | dependency: transitive 348 | description: 349 | name: typed_data 350 | url: "https://pub.dartlang.org" 351 | source: hosted 352 | version: "1.3.0" 353 | vector_math: 354 | dependency: transitive 355 | description: 356 | name: vector_math 357 | url: "https://pub.dartlang.org" 358 | source: hosted 359 | version: "2.1.0" 360 | webview_flutter: 361 | dependency: "direct main" 362 | description: 363 | name: webview_flutter 364 | url: "https://pub.dartlang.org" 365 | source: hosted 366 | version: "2.0.13" 367 | xml: 368 | dependency: transitive 369 | description: 370 | name: xml 371 | url: "https://pub.dartlang.org" 372 | source: hosted 373 | version: "5.1.2" 374 | sdks: 375 | dart: ">=2.14.0 <3.0.0" 376 | flutter: ">=2.5.0" 377 | -------------------------------------------------------------------------------- /lib/model/news.dart: -------------------------------------------------------------------------------- 1 | class News { 2 | String author; 3 | String title; 4 | String image; 5 | String published; 6 | String content; 7 | String url; 8 | String source; 9 | 10 | News( 11 | { 12 | required this.author, 13 | required this.title, 14 | required this.image, 15 | required this.published, 16 | required this.content, 17 | required this.url, 18 | required this.source 19 | } 20 | ); 21 | 22 | factory News.fromJson(Map json) { 23 | var imageUrl = "https://idtechsolusi.co.id/assets/img/no-image.png"; 24 | return News( 25 | author : json['author'] == null ? "" : json['author'], 26 | title : json['title'] == null ? "" : json['title'], 27 | image : json['urlToImage'] == null ? imageUrl : json['urlToImage'], 28 | published : json['publishedAt'] == null ? "" : json['publishedAt'], 29 | content : json['content'] == null ? "" : json['content'], 30 | url: json['url'] == null ? "" : json['url'], 31 | source: json['source']['name'] 32 | ); 33 | } 34 | } 35 | 36 | // class NewsList { 37 | // List newsL=[ 38 | // News( 39 | // author: 'Yuni Riadi', 40 | // title: 'Bocor di Tenaa Xiaomi CC11 Pro Punya Layar 4K - Selular.ID', 41 | // image: 'https://selular.id/wp-content/uploads/2021/07/Berita-Ke-3-Xiaomi-CC.jpg', 42 | // published: '2021-10-01', 43 | // content: 'Jakarta, Selular.ID – Pada Juli lalu informasi mengenai seri CC yang akan dirilis Xiaomi beredar. Melalui Wei Siqi, manajer produk dan juru bicara merek Xiaomi dengan jelas menyatakan bahwa model ser… \n Ligula amet, morbi risus, blandit turpis turpis habitant odio. Sem pharetra accumsan pulvinar mauris eget quis. Donec orci, vitae quisque a velit tristique consectetur malesuada. Scelerisque id mi dui ullamcorper. \n Vulputate ut arcu nulla dui, elementum condimentum. Amet donec purus hendrerit pharetra, mauris amet pharetra nibh. Eget sit vestibulum nibh semper neque nisi, purus. Tortor adipiscing dictum vel et sodales donec velit. Arcu senectus posuere sit adipiscing proin et nisi placerat vitae.' 44 | // ), 45 | // News( 46 | // author: 'M.Risman Noor', 47 | // title: 'Ponsel Android dan iPhone Tak Dapat Lagi Gunakan WhatsApp', 48 | // image: 'https://cdn-2.tstatic.net/banjarmasin/foto/bank/images/whatsapp-bakal-meluncurkan-5-fitur-baru-di-2021-ini.jpg', 49 | // published: '2021-10-01', 50 | // content: 'BANJARMASINPOST.CO.ID - Satu bulan lagi memasuki 1 November 2021 pengguna ponsel android maupun iOs bakal tak bisa lagi menggunakan WhatsApp.\r\nPonsel mana saja yang nantinya tak bisa menggunakan apli… \n Ligula amet, morbi risus, blandit turpis turpis habitant odio. Sem pharetra accumsan pulvinar mauris eget quis. Donec orci, vitae quisque a velit tristique consectetur malesuada. Scelerisque id mi dui ullamcorper. \n Vulputate ut arcu nulla dui, elementum condimentum. Amet donec purus hendrerit pharetra, mauris amet pharetra nibh. Eget sit vestibulum nibh semper neque nisi, purus. Tortor adipiscing dictum vel et sodales donec velit. Arcu senectus posuere sit adipiscing proin et nisi placerat vitae.' 51 | // ), 52 | // News( 53 | // author: 'Sahrul Sidiq', 54 | // title: 'HP Harga Rp1 Jutaan Terbaru 2021 Ada Oppo A31, Vivo S1 serta Samsung Galaxy M02', 55 | // image: 'https://cdn-2.tstatic.net/tribunnews/foto/bank/images/samsung-galaxy-a32-samsung-galaxy-a52-dan-samsung-galaxy-a52.jpg', 56 | // published: '2021-10-01', 57 | // content: 'MANTRA SUKABUMI - Berikut kami rangkum daftar HP android Rp.1 Jutaan dari berbagai merk ada dari Oppo A31, Vivo S1 hingga Samsung Galaxy M02.\r\nWalau dengan harga yang kisaran Rp.1 Jutaan, baik Oppo, … \n Ligula amet, morbi risus, blandit turpis turpis habitant odio. Sem pharetra accumsan pulvinar mauris eget quis. Donec orci, vitae quisque a velit tristique consectetur malesuada. Scelerisque id mi dui ullamcorper. \n Vulputate ut arcu nulla dui, elementum condimentum. Amet donec purus hendrerit pharetra, mauris amet pharetra nibh. Eget sit vestibulum nibh semper neque nisi, purus. Tortor adipiscing dictum vel et sodales donec velit. Arcu senectus posuere sit adipiscing proin et nisi placerat vitae.' 58 | // ), 59 | // News( 60 | // author: 'Intan Rakhmayanti Dewi', 61 | // title: 'Bos Microsoft Beberkan Kisah di Balik Gagalnya Akuisisi TikTok', 62 | // image: 'https://img.inews.co.id/media/600/files/inews_new/2021/10/01/Aplikasi_TikTok.jpg', 63 | // published: '2021-10-01', 64 | // content: 'JAKARTA, iNews.id  - Microsoft sempat ingin meminang TikTok tahun lalu. Namun, upaya untuk mengakuisisi perusahaan video pendek itu pada akhirnya tidak terlaksana. Bagaimana kisahnya?\r\nSelang setahun… \n Ligula amet, morbi risus, blandit turpis turpis habitant odio. Sem pharetra accumsan pulvinar mauris eget quis. Donec orci, vitae quisque a velit tristique consectetur malesuada. Scelerisque id mi dui ullamcorper. \n Vulputate ut arcu nulla dui, elementum condimentum. Amet donec purus hendrerit pharetra, mauris amet pharetra nibh. Eget sit vestibulum nibh semper neque nisi, purus. Tortor adipiscing dictum vel et sodales donec velit. Arcu senectus posuere sit adipiscing proin et nisi placerat vitae.' 65 | // ), 66 | // News( 67 | // author: 'Estu Suryowati', 68 | // title: 'Monitor Gaming LG UltraGear Ditopang Nvidia G-Sync dan Nano IPS', 69 | // image: 'https://images.soco.id/521-tips-mata-nyaman1.jpg.jpeg', 70 | // published: '2021-10-01', 71 | // content: 'JawaPos.com – Buat gamers yang bermain di perangkat PC, salah satu yang menunjang performa adalah monitor dengan kemampuan tinggi dalam menampilkan grafis. Di pasaran, cukup banyak tersedia monitor g… \n Ligula amet, morbi risus, blandit turpis turpis habitant odio. Sem pharetra accumsan pulvinar mauris eget quis. Donec orci, vitae quisque a velit tristique consectetur malesuada. Scelerisque id mi dui ullamcorper. \n Vulputate ut arcu nulla dui, elementum condimentum. Amet donec purus hendrerit pharetra, mauris amet pharetra nibh. Eget sit vestibulum nibh semper neque nisi, purus. Tortor adipiscing dictum vel et sodales donec velit. Arcu senectus posuere sit adipiscing proin et nisi placerat vitae.' 72 | // ), 73 | 74 | // ]; 75 | // } 76 | 77 | // class NewsHeadlines{ 78 | // List newsH=[ 79 | // News( 80 | // author: 'Fahri Zulfikar', 81 | // title: 'Sering Pakai Gadget untuk Sekolah Online? Awas Ada 200 Aplikasi Berbahaya', 82 | // image: 'https://awsimages.detik.net.id/api/wm/2021/02/21/begini-cara-belajar-asyik-sambil-bermain-untuk-anak-1_169.jpeg?wid=54&w=650&v=1&t=jpeg', 83 | // published: '2021-10-01', 84 | // content: 'Jakarta - Belum seluruh daerah menjalankan PTM Terbatas membuat siswa masih harus menjalani sekolah daring atau online dari rumah. Namun, siswa perlu hati-hati dalam menggunakan gadget karena terdapa… \n Ligula amet, morbi risus, blandit turpis turpis habitant odio. Sem pharetra accumsan pulvinar mauris eget quis. Donec orci, vitae quisque a velit tristique consectetur malesuada. Scelerisque id mi dui ullamcorper. \n Vulputate ut arcu nulla dui, elementum condimentum. Amet donec purus hendrerit pharetra, mauris amet pharetra nibh. Eget sit vestibulum nibh semper neque nisi, purus. Tortor adipiscing dictum vel et sodales donec velit. Arcu senectus posuere sit adipiscing proin et nisi placerat vitae.' 85 | // ), 86 | // News( 87 | // author: 'Kontan', 88 | // title: 'Tiga Pembalap Muda Bersaing Ketat di Puncak Klasemen Kelas Rising Star HRSC 2', 89 | // image: 'https://photo.kontan.co.id/photo/2021/10/01/1683201524p.jpg', 90 | // published: '2021-10-01', 91 | // content: 'Jakarta, 1 Oktober 2021 Seri keempat dari Honda Racing Simulator Championship (HRSC) musim kedua akan diselenggarakan akhir pekan ini, 2 Oktober 2021 dengan menggunakan sirkuit virtual Road Atlanta, … \n Ligula amet, morbi risus, blandit turpis turpis habitant odio. Sem pharetra accumsan pulvinar mauris eget quis. Donec orci, vitae quisque a velit tristique consectetur malesuada. Scelerisque id mi dui ullamcorper. \n Vulputate ut arcu nulla dui, elementum condimentum. Amet donec purus hendrerit pharetra, mauris amet pharetra nibh. Eget sit vestibulum nibh semper neque nisi, purus. Tortor adipiscing dictum vel et sodales donec velit. Arcu senectus posuere sit adipiscing proin et nisi placerat vitae.' 92 | // ), 93 | // News( 94 | // author: 'Agustinus Mario Damar', 95 | // title: 'Dell Perkenalkan 2 Laptop Gaming Terbaru dari Seri Alienware dan G-Series', 96 | // image: 'https://cdn0-production-images-kly.akamaized.net/1eA_BYbPWXYxtJaj98V095Xdd3U=/673x379/smart/filters:quality(75):strip_icc():format(jpeg)/kly-media-production/medias/3589310/original/065936600_1633063271-Dell_G15_family_photo_2.jpg', 97 | // published: '2021-10-01', 98 | // content: 'Liputan6.com, Jakarta - Dell Technologies baru saja meluncurkan laptop terbarunya, yakni Alienware M-Series dan Dell G-Series di Asia Selatan dan pasar berkembang Asia lainnya, termasuk di Indonesia.… \n Ligula amet, morbi risus, blandit turpis turpis habitant odio. Sem pharetra accumsan pulvinar mauris eget quis. Donec orci, vitae quisque a velit tristique consectetur malesuada. Scelerisque id mi dui ullamcorper. \n Vulputate ut arcu nulla dui, elementum condimentum. Amet donec purus hendrerit pharetra, mauris amet pharetra nibh. Eget sit vestibulum nibh semper neque nisi, purus. Tortor adipiscing dictum vel et sodales donec velit. Arcu senectus posuere sit adipiscing proin et nisi placerat vitae.' 99 | // ), 100 | // News( 101 | // author: 'Dommara Hadi S', 102 | // title: 'Pengguna iPhone enggan upgrade ke iOS 15', 103 | // image: 'https://img.tek.id/share/content/2021/10/01/45495/duh-pengguna-iphone-enggan-upgrade-ke-ios-15-GTH8isKZtR.jpg', 104 | // published: '2021-10-01', 105 | // content: 'Sepekan sudah setelah Apple menggulirkan secara resmi OS terbaru mereka untuk iPhone dan iPad. Para pengguna pengguna pun diharapkan untuk segera melakukan pembaruan ke iOS 15 dari OS lama mereka.\r\nT… \n Ligula amet, morbi risus, blandit turpis turpis habitant odio. Sem pharetra accumsan pulvinar mauris eget quis. Donec orci, vitae quisque a velit tristique consectetur malesuada. Scelerisque id mi dui ullamcorper. \n Vulputate ut arcu nulla dui, elementum condimentum. Amet donec purus hendrerit pharetra, mauris amet pharetra nibh. Eget sit vestibulum nibh semper neque nisi, purus. Tortor adipiscing dictum vel et sodales donec velit. Arcu senectus posuere sit adipiscing proin et nisi placerat vitae.' 106 | // ), 107 | // News( 108 | // author: 'Khoirunnisa', 109 | // title: 'Cristiano Amon: Snapdragon Insiders Hadir di Indonesia', 110 | // image: 'https://selular.id/wp-content/uploads/2021/10/Christiano-Amon.png', 111 | // published: '2021-10-01', 112 | // content: 'Jakarta, Selular.ID – Setelah diluncurkan secara global pada Maret 2021, Qualcomm hari ini secara resmi meluncurkan program Snapdragon Insiders di Indonesia. Program ini dibuat untuk mengumumkan beri… \n Ligula amet, morbi risus, blandit turpis turpis habitant odio. Sem pharetra accumsan pulvinar mauris eget quis. Donec orci, vitae quisque a velit tristique consectetur malesuada. Scelerisque id mi dui ullamcorper. \n Vulputate ut arcu nulla dui, elementum condimentum. Amet donec purus hendrerit pharetra, mauris amet pharetra nibh. Eget sit vestibulum nibh semper neque nisi, purus. Tortor adipiscing dictum vel et sodales donec velit. Arcu senectus posuere sit adipiscing proin et nisi placerat vitae.' 113 | // ), 114 | 115 | // ]; 116 | // } 117 | 118 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXCopyFilesBuildPhase section */ 19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 20 | isa = PBXCopyFilesBuildPhase; 21 | buildActionMask = 2147483647; 22 | dstPath = ""; 23 | dstSubfolderSpec = 10; 24 | files = ( 25 | ); 26 | name = "Embed Frameworks"; 27 | runOnlyForDeploymentPostprocessing = 0; 28 | }; 29 | /* End PBXCopyFilesBuildPhase section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 9740EEB11CF90186004384FC /* Flutter */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 65 | ); 66 | name = Flutter; 67 | sourceTree = ""; 68 | }; 69 | 97C146E51CF9000F007C117D = { 70 | isa = PBXGroup; 71 | children = ( 72 | 9740EEB11CF90186004384FC /* Flutter */, 73 | 97C146F01CF9000F007C117D /* Runner */, 74 | 97C146EF1CF9000F007C117D /* Products */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | 97C146EF1CF9000F007C117D /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 97C146EE1CF9000F007C117D /* Runner.app */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | 97C146F01CF9000F007C117D /* Runner */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 92 | 97C147021CF9000F007C117D /* Info.plist */, 93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 97 | ); 98 | path = Runner; 99 | sourceTree = ""; 100 | }; 101 | /* End PBXGroup section */ 102 | 103 | /* Begin PBXNativeTarget section */ 104 | 97C146ED1CF9000F007C117D /* Runner */ = { 105 | isa = PBXNativeTarget; 106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 107 | buildPhases = ( 108 | 9740EEB61CF901F6004384FC /* Run Script */, 109 | 97C146EA1CF9000F007C117D /* Sources */, 110 | 97C146EB1CF9000F007C117D /* Frameworks */, 111 | 97C146EC1CF9000F007C117D /* Resources */, 112 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 114 | ); 115 | buildRules = ( 116 | ); 117 | dependencies = ( 118 | ); 119 | name = Runner; 120 | productName = Runner; 121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 122 | productType = "com.apple.product-type.application"; 123 | }; 124 | /* End PBXNativeTarget section */ 125 | 126 | /* Begin PBXProject section */ 127 | 97C146E61CF9000F007C117D /* Project object */ = { 128 | isa = PBXProject; 129 | attributes = { 130 | LastUpgradeCheck = 1020; 131 | ORGANIZATIONNAME = ""; 132 | TargetAttributes = { 133 | 97C146ED1CF9000F007C117D = { 134 | CreatedOnToolsVersion = 7.3.1; 135 | LastSwiftMigration = 1100; 136 | }; 137 | }; 138 | }; 139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 140 | compatibilityVersion = "Xcode 9.3"; 141 | developmentRegion = en; 142 | hasScannedForEncodings = 0; 143 | knownRegions = ( 144 | en, 145 | Base, 146 | ); 147 | mainGroup = 97C146E51CF9000F007C117D; 148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 149 | projectDirPath = ""; 150 | projectRoot = ""; 151 | targets = ( 152 | 97C146ED1CF9000F007C117D /* Runner */, 153 | ); 154 | }; 155 | /* End PBXProject section */ 156 | 157 | /* Begin PBXResourcesBuildPhase section */ 158 | 97C146EC1CF9000F007C117D /* Resources */ = { 159 | isa = PBXResourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXShellScriptBuildPhase section */ 172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 173 | isa = PBXShellScriptBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | ); 177 | inputPaths = ( 178 | ); 179 | name = "Thin Binary"; 180 | outputPaths = ( 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | shellPath = /bin/sh; 184 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 185 | }; 186 | 9740EEB61CF901F6004384FC /* Run Script */ = { 187 | isa = PBXShellScriptBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | ); 191 | inputPaths = ( 192 | ); 193 | name = "Run Script"; 194 | outputPaths = ( 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | shellPath = /bin/sh; 198 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 199 | }; 200 | /* End PBXShellScriptBuildPhase section */ 201 | 202 | /* Begin PBXSourcesBuildPhase section */ 203 | 97C146EA1CF9000F007C117D /* Sources */ = { 204 | isa = PBXSourcesBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 208 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | /* End PBXSourcesBuildPhase section */ 213 | 214 | /* Begin PBXVariantGroup section */ 215 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 216 | isa = PBXVariantGroup; 217 | children = ( 218 | 97C146FB1CF9000F007C117D /* Base */, 219 | ); 220 | name = Main.storyboard; 221 | sourceTree = ""; 222 | }; 223 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 224 | isa = PBXVariantGroup; 225 | children = ( 226 | 97C147001CF9000F007C117D /* Base */, 227 | ); 228 | name = LaunchScreen.storyboard; 229 | sourceTree = ""; 230 | }; 231 | /* End PBXVariantGroup section */ 232 | 233 | /* Begin XCBuildConfiguration section */ 234 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 235 | isa = XCBuildConfiguration; 236 | buildSettings = { 237 | ALWAYS_SEARCH_USER_PATHS = NO; 238 | CLANG_ANALYZER_NONNULL = YES; 239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 240 | CLANG_CXX_LIBRARY = "libc++"; 241 | CLANG_ENABLE_MODULES = YES; 242 | CLANG_ENABLE_OBJC_ARC = YES; 243 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 244 | CLANG_WARN_BOOL_CONVERSION = YES; 245 | CLANG_WARN_COMMA = YES; 246 | CLANG_WARN_CONSTANT_CONVERSION = YES; 247 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 248 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 249 | CLANG_WARN_EMPTY_BODY = YES; 250 | CLANG_WARN_ENUM_CONVERSION = YES; 251 | CLANG_WARN_INFINITE_RECURSION = YES; 252 | CLANG_WARN_INT_CONVERSION = YES; 253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 258 | CLANG_WARN_STRICT_PROTOTYPES = YES; 259 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 260 | CLANG_WARN_UNREACHABLE_CODE = YES; 261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 263 | COPY_PHASE_STRIP = NO; 264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 265 | ENABLE_NS_ASSERTIONS = NO; 266 | ENABLE_STRICT_OBJC_MSGSEND = YES; 267 | GCC_C_LANGUAGE_STANDARD = gnu99; 268 | GCC_NO_COMMON_BLOCKS = YES; 269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 271 | GCC_WARN_UNDECLARED_SELECTOR = YES; 272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 273 | GCC_WARN_UNUSED_FUNCTION = YES; 274 | GCC_WARN_UNUSED_VARIABLE = YES; 275 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 276 | MTL_ENABLE_DEBUG_INFO = NO; 277 | SDKROOT = iphoneos; 278 | SUPPORTED_PLATFORMS = iphoneos; 279 | TARGETED_DEVICE_FAMILY = "1,2"; 280 | VALIDATE_PRODUCT = YES; 281 | }; 282 | name = Profile; 283 | }; 284 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 285 | isa = XCBuildConfiguration; 286 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 287 | buildSettings = { 288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 289 | CLANG_ENABLE_MODULES = YES; 290 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 291 | ENABLE_BITCODE = NO; 292 | INFOPLIST_FILE = Runner/Info.plist; 293 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 294 | PRODUCT_BUNDLE_IDENTIFIER = com.example.newsly; 295 | PRODUCT_NAME = "$(TARGET_NAME)"; 296 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 297 | SWIFT_VERSION = 5.0; 298 | VERSIONING_SYSTEM = "apple-generic"; 299 | }; 300 | name = Profile; 301 | }; 302 | 97C147031CF9000F007C117D /* Debug */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | ALWAYS_SEARCH_USER_PATHS = NO; 306 | CLANG_ANALYZER_NONNULL = YES; 307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 308 | CLANG_CXX_LIBRARY = "libc++"; 309 | CLANG_ENABLE_MODULES = YES; 310 | CLANG_ENABLE_OBJC_ARC = YES; 311 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 312 | CLANG_WARN_BOOL_CONVERSION = YES; 313 | CLANG_WARN_COMMA = YES; 314 | CLANG_WARN_CONSTANT_CONVERSION = YES; 315 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 316 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 317 | CLANG_WARN_EMPTY_BODY = YES; 318 | CLANG_WARN_ENUM_CONVERSION = YES; 319 | CLANG_WARN_INFINITE_RECURSION = YES; 320 | CLANG_WARN_INT_CONVERSION = YES; 321 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 322 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 323 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 324 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 325 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 326 | CLANG_WARN_STRICT_PROTOTYPES = YES; 327 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 328 | CLANG_WARN_UNREACHABLE_CODE = YES; 329 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 330 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 331 | COPY_PHASE_STRIP = NO; 332 | DEBUG_INFORMATION_FORMAT = dwarf; 333 | ENABLE_STRICT_OBJC_MSGSEND = YES; 334 | ENABLE_TESTABILITY = YES; 335 | GCC_C_LANGUAGE_STANDARD = gnu99; 336 | GCC_DYNAMIC_NO_PIC = NO; 337 | GCC_NO_COMMON_BLOCKS = YES; 338 | GCC_OPTIMIZATION_LEVEL = 0; 339 | GCC_PREPROCESSOR_DEFINITIONS = ( 340 | "DEBUG=1", 341 | "$(inherited)", 342 | ); 343 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 344 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 345 | GCC_WARN_UNDECLARED_SELECTOR = YES; 346 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 347 | GCC_WARN_UNUSED_FUNCTION = YES; 348 | GCC_WARN_UNUSED_VARIABLE = YES; 349 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 350 | MTL_ENABLE_DEBUG_INFO = YES; 351 | ONLY_ACTIVE_ARCH = YES; 352 | SDKROOT = iphoneos; 353 | TARGETED_DEVICE_FAMILY = "1,2"; 354 | }; 355 | name = Debug; 356 | }; 357 | 97C147041CF9000F007C117D /* Release */ = { 358 | isa = XCBuildConfiguration; 359 | buildSettings = { 360 | ALWAYS_SEARCH_USER_PATHS = NO; 361 | CLANG_ANALYZER_NONNULL = YES; 362 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 363 | CLANG_CXX_LIBRARY = "libc++"; 364 | CLANG_ENABLE_MODULES = YES; 365 | CLANG_ENABLE_OBJC_ARC = YES; 366 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 367 | CLANG_WARN_BOOL_CONVERSION = YES; 368 | CLANG_WARN_COMMA = YES; 369 | CLANG_WARN_CONSTANT_CONVERSION = YES; 370 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 371 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 372 | CLANG_WARN_EMPTY_BODY = YES; 373 | CLANG_WARN_ENUM_CONVERSION = YES; 374 | CLANG_WARN_INFINITE_RECURSION = YES; 375 | CLANG_WARN_INT_CONVERSION = YES; 376 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 377 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 378 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 379 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 380 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 381 | CLANG_WARN_STRICT_PROTOTYPES = YES; 382 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 383 | CLANG_WARN_UNREACHABLE_CODE = YES; 384 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 385 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 386 | COPY_PHASE_STRIP = NO; 387 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 388 | ENABLE_NS_ASSERTIONS = NO; 389 | ENABLE_STRICT_OBJC_MSGSEND = YES; 390 | GCC_C_LANGUAGE_STANDARD = gnu99; 391 | GCC_NO_COMMON_BLOCKS = YES; 392 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 393 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 394 | GCC_WARN_UNDECLARED_SELECTOR = YES; 395 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 396 | GCC_WARN_UNUSED_FUNCTION = YES; 397 | GCC_WARN_UNUSED_VARIABLE = YES; 398 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 399 | MTL_ENABLE_DEBUG_INFO = NO; 400 | SDKROOT = iphoneos; 401 | SUPPORTED_PLATFORMS = iphoneos; 402 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 403 | TARGETED_DEVICE_FAMILY = "1,2"; 404 | VALIDATE_PRODUCT = YES; 405 | }; 406 | name = Release; 407 | }; 408 | 97C147061CF9000F007C117D /* Debug */ = { 409 | isa = XCBuildConfiguration; 410 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 411 | buildSettings = { 412 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 413 | CLANG_ENABLE_MODULES = YES; 414 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 415 | ENABLE_BITCODE = NO; 416 | INFOPLIST_FILE = Runner/Info.plist; 417 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 418 | PRODUCT_BUNDLE_IDENTIFIER = com.example.newsly; 419 | PRODUCT_NAME = "$(TARGET_NAME)"; 420 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 421 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 422 | SWIFT_VERSION = 5.0; 423 | VERSIONING_SYSTEM = "apple-generic"; 424 | }; 425 | name = Debug; 426 | }; 427 | 97C147071CF9000F007C117D /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 430 | buildSettings = { 431 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 432 | CLANG_ENABLE_MODULES = YES; 433 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 434 | ENABLE_BITCODE = NO; 435 | INFOPLIST_FILE = Runner/Info.plist; 436 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 437 | PRODUCT_BUNDLE_IDENTIFIER = com.example.newsly; 438 | PRODUCT_NAME = "$(TARGET_NAME)"; 439 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 440 | SWIFT_VERSION = 5.0; 441 | VERSIONING_SYSTEM = "apple-generic"; 442 | }; 443 | name = Release; 444 | }; 445 | /* End XCBuildConfiguration section */ 446 | 447 | /* Begin XCConfigurationList section */ 448 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 449 | isa = XCConfigurationList; 450 | buildConfigurations = ( 451 | 97C147031CF9000F007C117D /* Debug */, 452 | 97C147041CF9000F007C117D /* Release */, 453 | 249021D3217E4FDB00AE95B9 /* Profile */, 454 | ); 455 | defaultConfigurationIsVisible = 0; 456 | defaultConfigurationName = Release; 457 | }; 458 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 459 | isa = XCConfigurationList; 460 | buildConfigurations = ( 461 | 97C147061CF9000F007C117D /* Debug */, 462 | 97C147071CF9000F007C117D /* Release */, 463 | 249021D4217E4FDB00AE95B9 /* Profile */, 464 | ); 465 | defaultConfigurationIsVisible = 0; 466 | defaultConfigurationName = Release; 467 | }; 468 | /* End XCConfigurationList section */ 469 | }; 470 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 471 | } 472 | --------------------------------------------------------------------------------