diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000..fcda34f0d6 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..af827079f1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# 백엔드 +.idea + diff --git a/README.md b/README.md index b0c42847c6..8d9430b04c 100644 --- a/README.md +++ b/README.md @@ -1,76 +1,310 @@ -# Welcome to GitHub +### [EYE-U](https://kookmin-sw.github.io/capstone-2024-23/) 객체탐지를 활용한 시각장애인용 보행 보조 앱

+ +
+ +## 📌 프로젝트 개요 | Project Abstract +**“혹시 흰 지팡이나 안내견에 의지하여 길을 걷는 시각장애인을 본 적 있나요?"**

+기존의 시각장애인을 위한 길 안내는 주로 점자판이나 안내견과 같은 수단을 사용해왔습니다.
+하지만 이러한 방법들은 여러 제약과 불편한 점이 있습니다.
+이 문제를 극복하기 위해 저희 EYE-U는 시각 장애가 있는 분들을 위한 내비게이션 앱을 개발하고자 합니다.

+본 프로젝트는 시각장애인 또는 저시력자분들을 주요 대상으로 하여, 그들이 일상 생활에서 겪는 보행의 불편함과 위험을 줄여주는 보행 보조 앱입니다.
+저희 앱은 실시간 음성 길 안내, 장애물 탐지, 위험물 알림 기능을 통해 이용자가 보다 안전하고 편리한 서비스를 경험할 수 있도록 도와줍니다.
+ +
+ +**“Have you ever seen a visually impaired person walking down the street relying on a white cane or guide dog?"** +

+Existing route guidance for the visually impaired has mainly used means such as Braille boards or guide dogs. However, these methods have several limitations and inconveniences. To overcome this problem, we at EYE-U want to develop a navigation app for people with visual impairments. + +This project is a walking assistance app targeting people who are visually impaired or have low vision and reduces the discomfort and risk of walking they experience in their daily lives. Our app helps users experience a safer and more convenient service through real-time voice directions, obstacle detection, and dangerous goods notification functions. +


+ + + +## 📘 주요 기능 | Key Features +- 탐지 모드 + - 장애물 및 위험물 탐지, 진동 경고 +- 보행 모드 + - 실시간 내비게이션 길 음성 안내 + 위험물 탐지 +
+ +## 💡 EYE-U POINT +- UI/UX + - 타겟 맞춤형 UI/UX + +- 보행자 친화 길안내 + - 목적지 출입구 및 보행로를 우선 + +- voice-all-in-one + - 불필요한 서비스 과정 제거 + - VOICE만을 이용해서 모든 기능 이용 가능 + +- 위험 물체 감지 + - 실시간 위험물 감지 및 진동 경고 +
+
+ + +## 📁 서비스 프로세스 | Sevice Process +image +
+
+ + +## 🎞 소개 영상 | Introduction video +[![소개영상](https://github.com/kookmin-sw/capstone-2024-23/assets/143046108/fbbb76cf-4f32-4450-8ba2-bba2e690552a)](https://www.youtube.com/watch?v=sgO9tWCrPbo) +
+

+ +## 🎞 시연 영상 | Demonstration video +[![시연영상](https://github.com/kookmin-sw/capstone-2024-23/assets/143046108/23c35d4a-64ef-480c-b2cc-998f91cf2b7a)](https://www.youtube.com/watch?v=FsVF8S9SSMI) +
+
+
+ + + +## 🧑🏻‍💻 팀 소개 | Introduction of team members +| **김호준** | **박성원** | **윤미나** | **이태영** | **정회창** | +|:--------------------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------:| +| [김호준
@hojuni9999](https://github.com/hojuni9999) | [박성원
@XungHi](https://github.com/XungHi) | [윤미나
@yoon-mina](https://github.com/yoon-mina) | [이태영
@LeeTaeYeong00](https://github.com/LeeTaeYeong00) | [정회창
@picetea44](https://github.com/picetea44) | +|****5206|****5207|****5209|****5211|****5212| +|AI |Front-end|Back-end|Front-end|Back-end| + + +
+ + +## ⤴ 배포 | Distribution +
+배포 +
+ +~~~ +- 어플리케이션 APK +1. Android Studio - build + +2. 해당 위치에 설치된 APK 파일을 배포한다. +capstone-2024-23\frontend\practice\build\app\outputs\flutter-apk + +~~~ + +
+
+
+ +## 🔎 실행 방법 | Execution method + +
+실행 방법 +
+ +~~~ +1. git clone +$ git clone https://github.com/kookmin-sw/capstone-2024-23.git + +2. Android Studio - build + +3. 해당 위치에 설치된 APK 파일 실행한다. +capstone-2024-23\frontend\practice\build\app\outputs\flutter-apk +~~~ + +
+
+ +
+ +## ⚙ 환경 설정 | Configuration Settings + +
+서버 실행 환경 설정 +
+ + +리눅스(우분투) 기준 +1. JAVA 설치 + +~~~ +# 1.apt update +$ sudo apt-get update + +# 2. java21 설치 +$ sudo apt-get install openjdk-21-jdk -캡스톤 팀 생성을 축하합니다. +# 3. 설치 후 버젼 확인 +$ java -version +~~~ -## 팀소개 및 페이지를 꾸며주세요. +2. 환경변수 설정 + +~~~ +# 환경변수 확인 (아무것도 안떠야 정상) +$ echo $JAVA_HOME -- 프로젝트 소개 - - 프로젝트 설치방법 및 데모, 사용방법, 프리뷰등을 readme.md에 작성. - - Api나 사용방법등 내용이 많을경우 wiki에 꾸미고 링크 추가. +# Java 절대 경로 확인 +$ which java +$ readlink -f "which java에서 나온 경로 기입" +# 절대 경로 shift + ctrl + c로 복사해두기 -- 팀페이지 꾸미기 - - 프로젝트 소개 및 팀원 소개 - - index.md 예시보고 수정. +# 환경변수 설정 진입 (초기화 방지) +$ vi /etc/profile -- GitHub Pages 리파지토리 Settings > Options > GitHub Pages - - Source를 marster branch - - Theme Chooser에서 태마선택 - - 수정후 팀페이지 확인하여 점검. +# 파일 최하단에 아래 문구 삽입 +#JAVA_HOME에 아까 복사한 절대 경로 삽입 +export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 +export PATH=$PATH:$JAVA_HOME/bin +export CLASSPATH=$JAVA_HOME/jre/lib -**팀페이지 주소** -> https://kookmin-sw.github.io/ '{{자신의 리파지토리 아이디}}' +# 환경변수 재확인 (경로가 떠야 정상) +$ echo $JAVA_HOME +~~~ -**예시)** 2023년 0조 https://kookmin-sw.github.io/capstone-2023-00/ +3. MySQL 설치 (원격 접속 설정 포함) + +~~~ +# mysql 설치 +$ apt-get install mysql-server +# mysql 설치 확인 +$ mysql --version -## 내용에 아래와 같은 내용들을 추가하세요. +# mysql 실행(택1) +$ mysql -u root -p # root 사용자 접근시 +$ mysql -u yoon -p # 특정 계정으로 접근시 ex) yoon 계정 사용 -### 1. 프로잭트 소개 +# mysql root 비밀번호 설정 (설치 후 반드시 설정) +# 1. mysql 설정 들어가기 +mysql> use mysql -프로젝트 +# 2. root 비밀번호 설정 +mysql> alter user "root"@"localhost" identified with mysql_native_password by "암호"; -### 2. 소개 영상 +# 3. 저장하기 +mysql> FLUSH PRIVILEGES; -프로젝트 소개하는 영상을 추가하세요 +# 사용자 계정 생성하기 +# 1. mysql 설정 들어가기 +mysql> use mysql -### 3. 팀 소개 +# 2. 외부 접근을 허용하는 사용자 추가하기(원격으로 mysql접근가능) +create user '계정명'@'%' identified by '0000'; -팀을 소개하세요. +# 3. 권한 부여해주기 +grant all privileges on *.* to '계정명'@'%'; + +# 4. 저장하기 +mysql> FLUSH PRIVILEGES; + +# 외부 접속 허용하기 +# 1. 최고 권한 부여 +$ sudo su + +# 2. 경로 이동하기 +$ cd/etc/mysql/mysql.conf.d + +# 3. 편집기 실행 +$ vi mysqld.cnf + +# 4. bind-address 수정하기 (i 눌러 수정모드 진입, 수정 후 ESC 누르고 :wq 를 통해 저장 후 종료) +bind-address = 0.0.0.0 + +# 5. 서버 재시작 +service mysql restart +~~~ + +4. git clone + +~~~ +$ git clone https://github.com/kookmin-sw/capstone-2024-23.git +~~~ + +5. Build & Upload + +~~~ +1. Intellij bootJar 이용하여 빌드 +2. FileZilla 업로드 +호스트에 자신이 만든 EC2 IP 주소 입력하고, 키 파일에 EC2 생성시 받은 PEM 키 넣어주기 +~~~ + +6. 서버 실행 + +~~~ +ssh -i ~/capstone2024Key.pem ubuntu@EC2 IP 주소 + +nohup java -jar 자바파일이름.jar & + +#prod 버젼으로 실행 +nohup java -jar -Dspring.profiles.active=prod 자바파일이름.jar & + +#config 별도 폴더 말고 외부의 application.properties 사용하기 +java -Dspring.config.location=classpath:/application.properties -jar yourapp.jar +~~~ +
+
+ +
+클라이언트 실행 환경설정 +
+ +1. 안드로이드스튜디오 Download (sdk 29 이상) +2. 플러터 3.19 버전 Download +3. git clone +$ git clone https://github.com/kookmin-sw/capstone-2024-23.git +4. frontend/pradtice/pubspec.yaml -> flutter_vision-master 경로 설정 (본인 경로) + +~~~ + path: /Users/yoon/StudioProjects/capstone-2024-23/frontend/flutter_vision-master +~~~ + +5. pubspec.yaml -> Pub.get Download + + +
+
+ +
+안드로이드 실행 환경설정 +
+ +1. usb 휴대폰 연결 +2. 설정 -> 화면 7번 터치 -> 개발자모드 실행 +3. 앱 실행 + +
+
+

+ +## 🗂 문서 | Document +
+ + + +
+ +
+ + 중간발표 자료 + + | + + 최종발표 자료 + + | + 사용자 매뉴얼 + + | + 포스터 + +
-팀원정보 및 담당이나 사진 및 SNS를 이용하여 소개하세요. - -### 4. 사용법 - -소스코드제출시 설치법이나 사용법을 작성하세요. - -### 5. 기타 - -추가적인 내용은 자유롭게 작성하세요. - - -## Markdown을 사용하여 내용꾸미기 - -Markdown은 작문을 스타일링하기위한 가볍고 사용하기 쉬운 구문입니다. 여기에는 다음을위한 규칙이 포함됩니다. - -```markdown -Syntax highlighted code block - -# Header 1 -## Header 2 -### Header 3 - -- Bulleted -- List - -1. Numbered -2. List - -**Bold** and _Italic_ and `Code` text - -[Link](url) and ![Image](src) -``` - -자세한 내용은 [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/). - -### Support or Contact - -readme 파일 생성에 추가적인 도움이 필요하면 [도움말](https://help.github.com/articles/about-readmes/) 이나 [contact support](https://github.com/contact) 을 이용하세요. diff --git a/ai/.DS_Store b/ai/.DS_Store new file mode 100644 index 0000000000..f0ab30677c Binary files /dev/null and b/ai/.DS_Store differ diff --git a/ai/Yolo/testIMG1.png b/ai/Yolo/testIMG1.png new file mode 100644 index 0000000000..ed54e75b14 Binary files /dev/null and b/ai/Yolo/testIMG1.png differ diff --git a/ai/Yolo/testIMG2.png b/ai/Yolo/testIMG2.png new file mode 100644 index 0000000000..8025d6d2de Binary files /dev/null and b/ai/Yolo/testIMG2.png differ diff --git a/ai/Yolo/yoloTrain.ipynb b/ai/Yolo/yoloTrain.ipynb new file mode 100644 index 0000000000..579e23914c --- /dev/null +++ b/ai/Yolo/yoloTrain.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"gpuType":"T4","authorship_tag":"ABX9TyPlyeNcB6A7f/4cBDI2HaHc"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"},"accelerator":"GPU"},"cells":[{"cell_type":"code","source":["from google.colab import drive\n","drive.mount('/content/drive')"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"iAFJTAg6wvZu","executionInfo":{"status":"ok","timestamp":1706683023072,"user_tz":-540,"elapsed":22776,"user":{"displayName":"‍김호준(학부생-소프트웨어전공)","userId":"06251474112980864102"}},"outputId":"fc2d62e4-bfab-458f-e918-ac6d028b7cd4"},"execution_count":1,"outputs":[{"output_type":"stream","name":"stdout","text":["Mounted at /content/drive\n"]}]},{"cell_type":"code","source":[" !git clone https://github.com/ultralytics/yolov5"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"eprCi99sESw8","executionInfo":{"status":"ok","timestamp":1706683028036,"user_tz":-540,"elapsed":3242,"user":{"displayName":"‍김호준(학부생-소프트웨어전공)","userId":"06251474112980864102"}},"outputId":"b4caa5c0-859c-4279-813f-277c8eb075ec"},"execution_count":2,"outputs":[{"output_type":"stream","name":"stdout","text":["Cloning into 'yolov5'...\n","remote: Enumerating objects: 16403, done.\u001b[K\n","remote: Counting objects: 100% (297/297), done.\u001b[K\n","remote: Compressing objects: 100% (220/220), done.\u001b[K\n","remote: Total 16403 (delta 154), reused 162 (delta 77), pack-reused 16106\u001b[K\n","Receiving objects: 100% (16403/16403), 15.15 MiB | 15.99 MiB/s, done.\n","Resolving deltas: 100% (11187/11187), done.\n"]}]},{"cell_type":"code","source":["%cd yolov5\n","!pip install -r requirements.txt # install dependencies"],"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":1000},"id":"ayhfVEg7EniC","executionInfo":{"status":"ok","timestamp":1706683038834,"user_tz":-540,"elapsed":9348,"user":{"displayName":"‍김호준(학부생-소프트웨어전공)","userId":"06251474112980864102"}},"outputId":"62787129-8e64-4e38-88db-8fb0a8ab339e"},"execution_count":3,"outputs":[{"output_type":"stream","name":"stdout","text":["/content/yolov5\n","Collecting gitpython>=3.1.30 (from -r requirements.txt (line 5))\n"," Downloading GitPython-3.1.41-py3-none-any.whl (196 kB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m196.4/196.4 kB\u001b[0m \u001b[31m4.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hRequirement already satisfied: matplotlib>=3.3 in /usr/local/lib/python3.10/dist-packages (from -r requirements.txt (line 6)) (3.7.1)\n","Requirement already satisfied: numpy>=1.23.5 in /usr/local/lib/python3.10/dist-packages (from -r requirements.txt (line 7)) (1.23.5)\n","Requirement already satisfied: opencv-python>=4.1.1 in /usr/local/lib/python3.10/dist-packages (from -r requirements.txt (line 8)) (4.8.0.76)\n","Collecting Pillow>=10.0.1 (from -r requirements.txt (line 9))\n"," Downloading pillow-10.2.0-cp310-cp310-manylinux_2_28_x86_64.whl (4.5 MB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m4.5/4.5 MB\u001b[0m \u001b[31m86.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hRequirement already satisfied: psutil in /usr/local/lib/python3.10/dist-packages (from -r requirements.txt (line 10)) (5.9.5)\n","Requirement already satisfied: PyYAML>=5.3.1 in /usr/local/lib/python3.10/dist-packages (from -r requirements.txt (line 11)) (6.0.1)\n","Requirement already satisfied: requests>=2.23.0 in /usr/local/lib/python3.10/dist-packages (from -r requirements.txt (line 12)) (2.31.0)\n","Requirement already satisfied: scipy>=1.4.1 in /usr/local/lib/python3.10/dist-packages (from -r requirements.txt (line 13)) (1.11.4)\n","Collecting thop>=0.1.1 (from -r requirements.txt (line 14))\n"," Downloading thop-0.1.1.post2209072238-py3-none-any.whl (15 kB)\n","Requirement already satisfied: torch>=1.8.0 in /usr/local/lib/python3.10/dist-packages (from -r requirements.txt (line 15)) (2.1.0+cu121)\n","Requirement already satisfied: torchvision>=0.9.0 in /usr/local/lib/python3.10/dist-packages (from -r requirements.txt (line 16)) (0.16.0+cu121)\n","Requirement already satisfied: tqdm>=4.64.0 in /usr/local/lib/python3.10/dist-packages (from -r requirements.txt (line 17)) (4.66.1)\n","Collecting ultralytics>=8.0.232 (from -r requirements.txt (line 18))\n"," Downloading ultralytics-8.1.8-py3-none-any.whl (709 kB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m709.4/709.4 kB\u001b[0m \u001b[31m64.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hRequirement already satisfied: pandas>=1.1.4 in /usr/local/lib/python3.10/dist-packages (from -r requirements.txt (line 27)) (1.5.3)\n","Requirement already satisfied: seaborn>=0.11.0 in /usr/local/lib/python3.10/dist-packages (from -r requirements.txt (line 28)) (0.13.1)\n","Requirement already satisfied: setuptools>=65.5.1 in /usr/local/lib/python3.10/dist-packages (from -r requirements.txt (line 42)) (67.7.2)\n","Collecting gitdb<5,>=4.0.1 (from gitpython>=3.1.30->-r requirements.txt (line 5))\n"," Downloading gitdb-4.0.11-py3-none-any.whl (62 kB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m62.7/62.7 kB\u001b[0m \u001b[31m8.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hRequirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.3->-r requirements.txt (line 6)) (1.2.0)\n","Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.3->-r requirements.txt (line 6)) (0.12.1)\n","Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.3->-r requirements.txt (line 6)) (4.47.2)\n","Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.3->-r requirements.txt (line 6)) (1.4.5)\n","Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.3->-r requirements.txt (line 6)) (23.2)\n","Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.3->-r requirements.txt (line 6)) (3.1.1)\n","Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.3->-r requirements.txt (line 6)) (2.8.2)\n","Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests>=2.23.0->-r requirements.txt (line 12)) (3.3.2)\n","Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests>=2.23.0->-r requirements.txt (line 12)) (3.6)\n","Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests>=2.23.0->-r requirements.txt (line 12)) (2.0.7)\n","Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests>=2.23.0->-r requirements.txt (line 12)) (2023.11.17)\n","Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from torch>=1.8.0->-r requirements.txt (line 15)) (3.13.1)\n","Requirement already satisfied: typing-extensions in /usr/local/lib/python3.10/dist-packages (from torch>=1.8.0->-r requirements.txt (line 15)) (4.5.0)\n","Requirement already satisfied: sympy in /usr/local/lib/python3.10/dist-packages (from torch>=1.8.0->-r requirements.txt (line 15)) (1.12)\n","Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from torch>=1.8.0->-r requirements.txt (line 15)) (3.2.1)\n","Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/dist-packages (from torch>=1.8.0->-r requirements.txt (line 15)) (3.1.3)\n","Requirement already satisfied: fsspec in /usr/local/lib/python3.10/dist-packages (from torch>=1.8.0->-r requirements.txt (line 15)) (2023.6.0)\n","Requirement already satisfied: triton==2.1.0 in /usr/local/lib/python3.10/dist-packages (from torch>=1.8.0->-r requirements.txt (line 15)) (2.1.0)\n","Requirement already satisfied: py-cpuinfo in /usr/local/lib/python3.10/dist-packages (from ultralytics>=8.0.232->-r requirements.txt (line 18)) (9.0.0)\n","Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas>=1.1.4->-r requirements.txt (line 27)) (2023.3.post1)\n","Collecting smmap<6,>=3.0.1 (from gitdb<5,>=4.0.1->gitpython>=3.1.30->-r requirements.txt (line 5))\n"," Downloading smmap-5.0.1-py3-none-any.whl (24 kB)\n","Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.7->matplotlib>=3.3->-r requirements.txt (line 6)) (1.16.0)\n","Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2->torch>=1.8.0->-r requirements.txt (line 15)) (2.1.4)\n","Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.10/dist-packages (from sympy->torch>=1.8.0->-r requirements.txt (line 15)) (1.3.0)\n","Installing collected packages: smmap, Pillow, gitdb, thop, gitpython, ultralytics\n"," Attempting uninstall: Pillow\n"," Found existing installation: Pillow 9.4.0\n"," Uninstalling Pillow-9.4.0:\n"," Successfully uninstalled Pillow-9.4.0\n","\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n","imageio 2.31.6 requires pillow<10.1.0,>=8.3.2, but you have pillow 10.2.0 which is incompatible.\u001b[0m\u001b[31m\n","\u001b[0mSuccessfully installed Pillow-10.2.0 gitdb-4.0.11 gitpython-3.1.41 smmap-5.0.1 thop-0.1.1.post2209072238 ultralytics-8.1.8\n"]},{"output_type":"display_data","data":{"application/vnd.colab-display-data+json":{"pip_warning":{"packages":["PIL"]}}},"metadata":{}}]},{"cell_type":"code","source":["!pip install roboflow\n","\n","from roboflow import Roboflow\n","rf = Roboflow(api_key=\"ScrNlmSgFQq1hQrLe8G6\")\n","project = rf.workspace(\"pedestrianobstacle\").project(\"pedestrianobstacledetection\")\n","dataset = project.version(1).download(\"yolov5\")\n"],"metadata":{"id":"JlGD_35DE1kK","colab":{"base_uri":"https://localhost:8080/","height":1000},"executionInfo":{"status":"ok","timestamp":1706683101644,"user_tz":-540,"elapsed":59915,"user":{"displayName":"‍김호준(학부생-소프트웨어전공)","userId":"06251474112980864102"}},"outputId":"ea20eff9-5522-4a1c-a89e-458d34ecd2bf"},"execution_count":4,"outputs":[{"output_type":"stream","name":"stdout","text":["Collecting roboflow\n"," Downloading roboflow-1.1.17-py3-none-any.whl (70 kB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m70.0/70.0 kB\u001b[0m \u001b[31m1.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hCollecting certifi==2023.7.22 (from roboflow)\n"," Downloading certifi-2023.7.22-py3-none-any.whl (158 kB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m158.3/158.3 kB\u001b[0m \u001b[31m8.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hCollecting chardet==4.0.0 (from roboflow)\n"," Downloading chardet-4.0.0-py2.py3-none-any.whl (178 kB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m178.7/178.7 kB\u001b[0m \u001b[31m24.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hCollecting cycler==0.10.0 (from roboflow)\n"," Downloading cycler-0.10.0-py2.py3-none-any.whl (6.5 kB)\n","Collecting idna==2.10 (from roboflow)\n"," Downloading idna-2.10-py2.py3-none-any.whl (58 kB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m58.8/58.8 kB\u001b[0m \u001b[31m8.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hRequirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.10/dist-packages (from roboflow) (1.4.5)\n","Requirement already satisfied: matplotlib in /usr/local/lib/python3.10/dist-packages (from roboflow) (3.7.1)\n","Requirement already satisfied: numpy>=1.18.5 in /usr/local/lib/python3.10/dist-packages (from roboflow) (1.23.5)\n","Collecting opencv-python-headless==4.8.0.74 (from roboflow)\n"," Downloading opencv_python_headless-4.8.0.74-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (49.1 MB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m49.1/49.1 MB\u001b[0m \u001b[31m12.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hRequirement already satisfied: Pillow>=7.1.2 in /usr/local/lib/python3.10/dist-packages (from roboflow) (10.2.0)\n","Requirement already satisfied: python-dateutil in /usr/local/lib/python3.10/dist-packages (from roboflow) (2.8.2)\n","Collecting python-dotenv (from roboflow)\n"," Downloading python_dotenv-1.0.1-py3-none-any.whl (19 kB)\n","Requirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (from roboflow) (2.31.0)\n","Requirement already satisfied: six in /usr/local/lib/python3.10/dist-packages (from roboflow) (1.16.0)\n","Collecting supervision (from roboflow)\n"," Downloading supervision-0.18.0-py3-none-any.whl (86 kB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m86.7/86.7 kB\u001b[0m \u001b[31m12.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hRequirement already satisfied: urllib3>=1.26.6 in /usr/local/lib/python3.10/dist-packages (from roboflow) (2.0.7)\n","Requirement already satisfied: tqdm>=4.41.0 in /usr/local/lib/python3.10/dist-packages (from roboflow) (4.66.1)\n","Requirement already satisfied: PyYAML>=5.3.1 in /usr/local/lib/python3.10/dist-packages (from roboflow) (6.0.1)\n","Collecting requests-toolbelt (from roboflow)\n"," Downloading requests_toolbelt-1.0.0-py2.py3-none-any.whl (54 kB)\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m54.5/54.5 kB\u001b[0m \u001b[31m8.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n","\u001b[?25hCollecting python-magic (from roboflow)\n"," Downloading python_magic-0.4.27-py2.py3-none-any.whl (13 kB)\n","Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->roboflow) (1.2.0)\n","Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->roboflow) (4.47.2)\n","Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->roboflow) (23.2)\n","Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->roboflow) (3.1.1)\n","Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests->roboflow) (3.3.2)\n","Requirement already satisfied: defusedxml<0.8.0,>=0.7.1 in /usr/local/lib/python3.10/dist-packages (from supervision->roboflow) (0.7.1)\n","Requirement already satisfied: scipy<2.0.0,>=1.10.0 in /usr/local/lib/python3.10/dist-packages (from supervision->roboflow) (1.11.4)\n","Installing collected packages: python-magic, python-dotenv, opencv-python-headless, idna, cycler, chardet, certifi, supervision, requests-toolbelt, roboflow\n"," Attempting uninstall: opencv-python-headless\n"," Found existing installation: opencv-python-headless 4.9.0.80\n"," Uninstalling opencv-python-headless-4.9.0.80:\n"," Successfully uninstalled opencv-python-headless-4.9.0.80\n"," Attempting uninstall: idna\n"," Found existing installation: idna 3.6\n"," Uninstalling idna-3.6:\n"," Successfully uninstalled idna-3.6\n"," Attempting uninstall: cycler\n"," Found existing installation: cycler 0.12.1\n"," Uninstalling cycler-0.12.1:\n"," Successfully uninstalled cycler-0.12.1\n"," Attempting uninstall: chardet\n"," Found existing installation: chardet 5.2.0\n"," Uninstalling chardet-5.2.0:\n"," Successfully uninstalled chardet-5.2.0\n"," Attempting uninstall: certifi\n"," Found existing installation: certifi 2023.11.17\n"," Uninstalling certifi-2023.11.17:\n"," Successfully uninstalled certifi-2023.11.17\n","\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n","lida 0.0.10 requires fastapi, which is not installed.\n","lida 0.0.10 requires kaleido, which is not installed.\n","lida 0.0.10 requires python-multipart, which is not installed.\n","lida 0.0.10 requires uvicorn, which is not installed.\u001b[0m\u001b[31m\n","\u001b[0mSuccessfully installed certifi-2023.7.22 chardet-4.0.0 cycler-0.10.0 idna-2.10 opencv-python-headless-4.8.0.74 python-dotenv-1.0.1 python-magic-0.4.27 requests-toolbelt-1.0.0 roboflow-1.1.17 supervision-0.18.0\n"]},{"output_type":"display_data","data":{"application/vnd.colab-display-data+json":{"pip_warning":{"packages":["certifi","cycler"]}}},"metadata":{}},{"output_type":"stream","name":"stdout","text":["loading Roboflow workspace...\n","loading Roboflow project...\n"]},{"output_type":"stream","name":"stderr","text":["Downloading Dataset Version Zip in PedestrianObstacleDetection-1 to yolov5pytorch:: 100%|██████████| 704267/704267 [00:37<00:00, 18567.50it/s]"]},{"output_type":"stream","name":"stdout","text":["\n"]},{"output_type":"stream","name":"stderr","text":["\n","Extracting Dataset Version Zip to PedestrianObstacleDetection-1 in yolov5pytorch:: 100%|██████████| 15884/15884 [00:03<00:00, 4354.64it/s]\n"]}]},{"cell_type":"code","source":["from glob import glob"],"metadata":{"id":"7xcCDdg9PIJN","executionInfo":{"status":"ok","timestamp":1706683123693,"user_tz":-540,"elapsed":514,"user":{"displayName":"‍김호준(학부생-소프트웨어전공)","userId":"06251474112980864102"}}},"execution_count":5,"outputs":[]},{"cell_type":"code","source":["img_list = glob('/content/yolov5/PedestrianObstacleDetection-1/train/images/*.jpg') # 트레인 이미지 경로\n","val_img_list = glob('/content/yolov5/PedestrianObstacleDetection-1/test/images/*.jpg') # 테스트 이미지 경로"],"metadata":{"id":"8TTJR2a6PcEU","executionInfo":{"status":"ok","timestamp":1706683181395,"user_tz":-540,"elapsed":10,"user":{"displayName":"‍김호준(학부생-소프트웨어전공)","userId":"06251474112980864102"}}},"execution_count":6,"outputs":[]},{"cell_type":"code","source":["with open('/content/yolov5/train.txt', 'w') as f:\n"," f.write('\\n'.join(img_list) + '\\n')\n","\n","\n","with open('/content/yolov5/test.txt', 'w') as f:\n"," f.write('\\n'.join(val_img_list) + '\\n')"],"metadata":{"id":"Z53TP1X4PqMz","executionInfo":{"status":"ok","timestamp":1706683243518,"user_tz":-540,"elapsed":6,"user":{"displayName":"‍김호준(학부생-소프트웨어전공)","userId":"06251474112980864102"}}},"execution_count":8,"outputs":[]},{"cell_type":"code","source":["!python train.py --img 416 --batch 16 --epochs 50 --data /content/yolov5/PedestrianObstacleDetection-1/data.yaml --weights yolov5x.pt --name result_jetbot --cfg ./models/yolov5x.yaml"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"jCKbKgeNP15y","executionInfo":{"status":"ok","timestamp":1706698614319,"user_tz":-540,"elapsed":15158357,"user":{"displayName":"‍김호준(학부생-소프트웨어전공)","userId":"06251474112980864102"}},"outputId":"d88b6382-2958-45dd-e296-4e7e3aad0522"},"execution_count":10,"outputs":[{"output_type":"stream","name":"stdout","text":["2024-01-31 06:44:21.865733: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:9261] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n","2024-01-31 06:44:21.865781: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:607] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n","2024-01-31 06:44:21.867036: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1515] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n","\u001b[34m\u001b[1mtrain: \u001b[0mweights=yolov5x.pt, cfg=./models/yolov5x.yaml, data=/content/yolov5/PedestrianObstacleDetection-1/data.yaml, hyp=data/hyps/hyp.scratch-low.yaml, epochs=50, batch_size=16, imgsz=416, rect=False, resume=False, nosave=False, noval=False, noautoanchor=False, noplots=False, evolve=None, evolve_population=data/hyps, resume_evolve=None, bucket=, cache=None, image_weights=False, device=, multi_scale=False, single_cls=False, optimizer=SGD, sync_bn=False, workers=8, project=runs/train, name=result_jetbot, exist_ok=False, quad=False, cos_lr=False, label_smoothing=0.0, patience=100, freeze=[0], save_period=-1, seed=0, local_rank=-1, entity=None, upload_dataset=False, bbox_interval=-1, artifact_alias=latest, ndjson_console=False, ndjson_file=False\n","\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov5 ✅\n","YOLOv5 🚀 v7.0-282-g9cdbd1de Python-3.10.12 torch-2.1.0+cu121 CUDA:0 (Tesla T4, 15102MiB)\n","\n","\u001b[34m\u001b[1mhyperparameters: \u001b[0mlr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0\n","\u001b[34m\u001b[1mComet: \u001b[0mrun 'pip install comet_ml' to automatically track and visualize YOLOv5 🚀 runs in Comet\n","\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train', view at http://localhost:6006/\n","Downloading https://ultralytics.com/assets/Arial.ttf to /root/.config/Ultralytics/Arial.ttf...\n","100% 755k/755k [00:00<00:00, 123MB/s]\n","Downloading https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x.pt to yolov5x.pt...\n","100% 166M/166M [00:00<00:00, 219MB/s]\n","\n","Overriding model.yaml nc=80 with nc=22\n","\n"," from n params module arguments \n"," 0 -1 1 8800 models.common.Conv [3, 80, 6, 2, 2] \n"," 1 -1 1 115520 models.common.Conv [80, 160, 3, 2] \n"," 2 -1 4 309120 models.common.C3 [160, 160, 4] \n"," 3 -1 1 461440 models.common.Conv [160, 320, 3, 2] \n"," 4 -1 8 2259200 models.common.C3 [320, 320, 8] \n"," 5 -1 1 1844480 models.common.Conv [320, 640, 3, 2] \n"," 6 -1 12 13125120 models.common.C3 [640, 640, 12] \n"," 7 -1 1 7375360 models.common.Conv [640, 1280, 3, 2] \n"," 8 -1 4 19676160 models.common.C3 [1280, 1280, 4] \n"," 9 -1 1 4099840 models.common.SPPF [1280, 1280, 5] \n"," 10 -1 1 820480 models.common.Conv [1280, 640, 1, 1] \n"," 11 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n"," 12 [-1, 6] 1 0 models.common.Concat [1] \n"," 13 -1 4 5332480 models.common.C3 [1280, 640, 4, False] \n"," 14 -1 1 205440 models.common.Conv [640, 320, 1, 1] \n"," 15 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n"," 16 [-1, 4] 1 0 models.common.Concat [1] \n"," 17 -1 4 1335040 models.common.C3 [640, 320, 4, False] \n"," 18 -1 1 922240 models.common.Conv [320, 320, 3, 2] \n"," 19 [-1, 14] 1 0 models.common.Concat [1] \n"," 20 -1 4 4922880 models.common.C3 [640, 640, 4, False] \n"," 21 -1 1 3687680 models.common.Conv [640, 640, 3, 2] \n"," 22 [-1, 10] 1 0 models.common.Concat [1] \n"," 23 -1 4 19676160 models.common.C3 [1280, 1280, 4, False] \n"," 24 [17, 20, 23] 1 181683 models.yolo.Detect [22, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [320, 640, 1280]]\n","YOLOv5x summary: 445 layers, 86359123 parameters, 86359123 gradients, 205.1 GFLOPs\n","\n","Transferred 738/745 items from yolov5x.pt\n","\u001b[34m\u001b[1mAMP: \u001b[0mchecks passed ✅\n","\u001b[34m\u001b[1moptimizer:\u001b[0m SGD(lr=0.01) with parameter groups 123 weight(decay=0.0), 126 weight(decay=0.0005), 126 bias\n","\u001b[34m\u001b[1malbumentations: \u001b[0mBlur(p=0.01, blur_limit=(3, 7)), MedianBlur(p=0.01, blur_limit=(3, 7)), ToGray(p=0.01), CLAHE(p=0.01, clip_limit=(1, 4.0), tile_grid_size=(8, 8))\n","\u001b[34m\u001b[1mtrain: \u001b[0mScanning /content/yolov5/train... 6947 images, 8 backgrounds, 0 corrupt: 100% 6947/6947 [00:03<00:00, 1783.59it/s]\n","\u001b[34m\u001b[1mtrain: \u001b[0mNew cache created: /content/yolov5/train.cache\n","\u001b[34m\u001b[1mval: \u001b[0mScanning /content/yolov5/PedestrianObstacleDetection-1/valid/labels... 650 images, 0 backgrounds, 0 corrupt: 100% 650/650 [00:01<00:00, 400.30it/s]\n","\u001b[34m\u001b[1mval: \u001b[0mNew cache created: /content/yolov5/PedestrianObstacleDetection-1/valid/labels.cache\n","\n","\u001b[34m\u001b[1mAutoAnchor: \u001b[0m3.98 anchors/target, 0.993 Best Possible Recall (BPR). Current anchors are a good fit to dataset ✅\n","Plotting labels to runs/train/result_jetbot/labels.jpg... \n","Image sizes 416 train, 416 val\n","Using 2 dataloader workers\n","Logging results to \u001b[1mruns/train/result_jetbot\u001b[0m\n","Starting training for 50 epochs...\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 0/49 7.04G 0.06824 0.02331 0.0614 8 416: 100% 435/435 [04:49<00:00, 1.50it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:15<00:00, 1.39it/s]\n"," all 650 992 0.615 0.338 0.348 0.181\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 1/49 7.94G 0.05019 0.01804 0.03145 7 416: 100% 435/435 [04:45<00:00, 1.52it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.54it/s]\n"," all 650 992 0.563 0.595 0.61 0.313\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 2/49 7.94G 0.04766 0.01643 0.02103 9 416: 100% 435/435 [04:42<00:00, 1.54it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:14<00:00, 1.45it/s]\n"," all 650 992 0.552 0.633 0.625 0.31\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 3/49 7.94G 0.04502 0.01698 0.01966 5 416: 100% 435/435 [04:37<00:00, 1.57it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.53it/s]\n"," all 650 992 0.618 0.657 0.672 0.385\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 4/49 7.94G 0.04285 0.01719 0.01778 14 416: 100% 435/435 [04:37<00:00, 1.57it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:15<00:00, 1.38it/s]\n"," all 650 992 0.627 0.699 0.695 0.413\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 5/49 7.94G 0.04114 0.01644 0.01515 9 416: 100% 435/435 [04:38<00:00, 1.56it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.51it/s]\n"," all 650 992 0.702 0.692 0.699 0.408\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 6/49 7.94G 0.04006 0.01606 0.01415 13 416: 100% 435/435 [04:40<00:00, 1.55it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:15<00:00, 1.33it/s]\n"," all 650 992 0.588 0.697 0.707 0.421\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 7/49 7.94G 0.0387 0.01577 0.01294 10 416: 100% 435/435 [04:41<00:00, 1.55it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.53it/s]\n"," all 650 992 0.646 0.737 0.718 0.437\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 8/49 7.94G 0.03741 0.01568 0.01231 12 416: 100% 435/435 [04:39<00:00, 1.56it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:14<00:00, 1.48it/s]\n"," all 650 992 0.745 0.76 0.77 0.475\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 9/49 7.94G 0.03635 0.01522 0.01148 10 416: 100% 435/435 [04:37<00:00, 1.57it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:14<00:00, 1.50it/s]\n"," all 650 992 0.745 0.777 0.799 0.491\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 10/49 7.94G 0.03527 0.01482 0.01092 10 416: 100% 435/435 [04:40<00:00, 1.55it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.51it/s]\n"," all 650 992 0.725 0.771 0.771 0.488\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 11/49 7.94G 0.03503 0.01456 0.009927 7 416: 100% 435/435 [04:38<00:00, 1.56it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.51it/s]\n"," all 650 992 0.757 0.779 0.807 0.498\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 12/49 7.94G 0.03386 0.01426 0.009769 7 416: 100% 435/435 [04:40<00:00, 1.55it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.53it/s]\n"," all 650 992 0.728 0.785 0.796 0.492\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 13/49 7.94G 0.03322 0.01399 0.008836 6 416: 100% 435/435 [04:38<00:00, 1.56it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:14<00:00, 1.50it/s]\n"," all 650 992 0.711 0.81 0.808 0.524\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 14/49 7.94G 0.03256 0.01384 0.008151 10 416: 100% 435/435 [04:38<00:00, 1.56it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:16<00:00, 1.27it/s]\n"," all 650 992 0.772 0.803 0.821 0.517\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 15/49 7.94G 0.03159 0.01346 0.008174 12 416: 100% 435/435 [04:39<00:00, 1.56it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:14<00:00, 1.49it/s]\n"," all 650 992 0.753 0.833 0.826 0.54\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 16/49 7.94G 0.0311 0.01331 0.007897 9 416: 100% 435/435 [04:41<00:00, 1.54it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:15<00:00, 1.35it/s]\n"," all 650 992 0.749 0.854 0.84 0.562\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 17/49 7.94G 0.03076 0.01306 0.007258 6 416: 100% 435/435 [04:42<00:00, 1.54it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:15<00:00, 1.40it/s]\n"," all 650 992 0.762 0.834 0.809 0.531\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 18/49 7.94G 0.02984 0.01271 0.006808 11 416: 100% 435/435 [04:55<00:00, 1.47it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:14<00:00, 1.48it/s]\n"," all 650 992 0.773 0.834 0.835 0.55\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 19/49 7.94G 0.02901 0.0126 0.006493 7 416: 100% 435/435 [04:50<00:00, 1.50it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.51it/s]\n"," all 650 992 0.784 0.821 0.83 0.568\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 20/49 7.94G 0.02846 0.01245 0.006481 5 416: 100% 435/435 [04:49<00:00, 1.50it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.52it/s]\n"," all 650 992 0.782 0.826 0.828 0.559\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 21/49 7.94G 0.0283 0.01239 0.006301 13 416: 100% 435/435 [04:40<00:00, 1.55it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:14<00:00, 1.46it/s]\n"," all 650 992 0.775 0.829 0.834 0.567\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 22/49 7.94G 0.02794 0.01208 0.005892 11 416: 100% 435/435 [04:42<00:00, 1.54it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:15<00:00, 1.32it/s]\n"," all 650 992 0.791 0.838 0.825 0.561\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 23/49 7.94G 0.02718 0.01198 0.005579 8 416: 100% 435/435 [04:41<00:00, 1.54it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:14<00:00, 1.50it/s]\n"," all 650 992 0.796 0.854 0.838 0.571\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 24/49 7.94G 0.02648 0.01173 0.005379 10 416: 100% 435/435 [04:41<00:00, 1.55it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:14<00:00, 1.47it/s]\n"," all 650 992 0.801 0.843 0.839 0.588\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 25/49 7.94G 0.02647 0.01148 0.005111 6 416: 100% 435/435 [04:45<00:00, 1.52it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.51it/s]\n"," all 650 992 0.801 0.845 0.839 0.584\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 26/49 7.94G 0.02564 0.01145 0.005002 5 416: 100% 435/435 [04:42<00:00, 1.54it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.51it/s]\n"," all 650 992 0.792 0.847 0.838 0.587\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 27/49 7.94G 0.02529 0.01118 0.004875 12 416: 100% 435/435 [04:42<00:00, 1.54it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.51it/s]\n"," all 650 992 0.809 0.833 0.838 0.587\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 28/49 7.94G 0.02495 0.01111 0.004655 6 416: 100% 435/435 [04:40<00:00, 1.55it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.53it/s]\n"," all 650 992 0.796 0.842 0.842 0.598\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 29/49 7.94G 0.02422 0.01074 0.004205 9 416: 100% 435/435 [04:35<00:00, 1.58it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:14<00:00, 1.47it/s]\n"," all 650 992 0.805 0.82 0.843 0.592\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 30/49 7.94G 0.02365 0.01071 0.0041 16 416: 100% 435/435 [04:34<00:00, 1.59it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.52it/s]\n"," all 650 992 0.782 0.853 0.84 0.597\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 31/49 7.94G 0.02325 0.01048 0.004035 4 416: 100% 435/435 [04:34<00:00, 1.59it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:15<00:00, 1.34it/s]\n"," all 650 992 0.796 0.851 0.838 0.588\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 32/49 7.94G 0.02307 0.01036 0.003888 12 416: 100% 435/435 [04:39<00:00, 1.56it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.52it/s]\n"," all 650 992 0.782 0.835 0.846 0.608\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 33/49 7.94G 0.02227 0.00989 0.003709 5 416: 100% 435/435 [04:39<00:00, 1.56it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.55it/s]\n"," all 650 992 0.774 0.864 0.84 0.605\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 34/49 7.94G 0.02208 0.00998 0.003492 7 416: 100% 435/435 [04:37<00:00, 1.57it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.52it/s]\n"," all 650 992 0.782 0.864 0.837 0.6\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 35/49 7.94G 0.02145 0.009874 0.003341 7 416: 100% 435/435 [04:40<00:00, 1.55it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.53it/s]\n"," all 650 992 0.806 0.835 0.844 0.602\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 36/49 7.94G 0.02103 0.009554 0.003448 9 416: 100% 435/435 [04:37<00:00, 1.57it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.50it/s]\n"," all 650 992 0.803 0.847 0.846 0.606\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 37/49 7.94G 0.02048 0.009486 0.003152 8 416: 100% 435/435 [04:37<00:00, 1.57it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.51it/s]\n"," all 650 992 0.784 0.867 0.843 0.599\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 38/49 7.94G 0.0202 0.009362 0.003061 8 416: 100% 435/435 [04:38<00:00, 1.56it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.54it/s]\n"," all 650 992 0.798 0.85 0.84 0.6\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 39/49 7.94G 0.01993 0.009138 0.002942 9 416: 100% 435/435 [04:41<00:00, 1.54it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.51it/s]\n"," all 650 992 0.799 0.837 0.845 0.608\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 40/49 7.94G 0.01938 0.009116 0.00281 7 416: 100% 435/435 [04:35<00:00, 1.58it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.52it/s]\n"," all 650 992 0.793 0.844 0.838 0.606\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 41/49 7.94G 0.01886 0.009073 0.002685 9 416: 100% 435/435 [04:38<00:00, 1.56it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.55it/s]\n"," all 650 992 0.799 0.836 0.838 0.604\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 42/49 7.94G 0.01844 0.00864 0.002538 12 416: 100% 435/435 [04:36<00:00, 1.58it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:14<00:00, 1.49it/s]\n"," all 650 992 0.804 0.836 0.84 0.606\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 43/49 7.94G 0.018 0.008675 0.002357 4 416: 100% 435/435 [04:37<00:00, 1.57it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.56it/s]\n"," all 650 992 0.794 0.845 0.838 0.608\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 44/49 7.94G 0.01788 0.00845 0.002339 9 416: 100% 435/435 [04:42<00:00, 1.54it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.53it/s]\n"," all 650 992 0.823 0.799 0.836 0.606\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 45/49 7.94G 0.01735 0.008235 0.002327 5 416: 100% 435/435 [04:32<00:00, 1.60it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.55it/s]\n"," all 650 992 0.794 0.841 0.833 0.603\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 46/49 7.94G 0.01714 0.008277 0.00223 10 416: 100% 435/435 [04:32<00:00, 1.60it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.60it/s]\n"," all 650 992 0.786 0.844 0.84 0.609\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 47/49 7.94G 0.01653 0.008295 0.002178 7 416: 100% 435/435 [04:30<00:00, 1.61it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.57it/s]\n"," all 650 992 0.837 0.786 0.841 0.613\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 48/49 7.94G 0.01617 0.008067 0.002103 10 416: 100% 435/435 [04:33<00:00, 1.59it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:15<00:00, 1.38it/s]\n"," all 650 992 0.829 0.798 0.845 0.616\n","\n"," Epoch GPU_mem box_loss obj_loss cls_loss Instances Size\n"," 49/49 7.94G 0.01572 0.007886 0.001944 7 416: 100% 435/435 [04:42<00:00, 1.54it/s]\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:13<00:00, 1.59it/s]\n"," all 650 992 0.791 0.843 0.84 0.618\n","\n","50 epochs completed in 4.191 hours.\n","Optimizer stripped from runs/train/result_jetbot/weights/last.pt, 173.3MB\n","Optimizer stripped from runs/train/result_jetbot/weights/best.pt, 173.3MB\n","\n","Validating runs/train/result_jetbot/weights/best.pt...\n","Fusing layers... \n","YOLOv5x summary: 322 layers, 86314723 parameters, 0 gradients, 204.2 GFLOPs\n"," Class Images Instances P R mAP50 mAP50-95: 100% 21/21 [00:15<00:00, 1.38it/s]\n"," all 650 992 0.791 0.843 0.84 0.618\n"," bad road 650 59 0.811 0.898 0.884 0.589\n"," car 650 104 0.859 0.875 0.905 0.698\n"," chair 650 24 0.965 0.833 0.891 0.696\n"," door 650 9 0.911 1 0.995 0.961\n"," drain 650 29 1 0.982 0.995 0.687\n"," fence 650 21 0.836 0.952 0.957 0.827\n"," garbage bin 650 11 0.789 1 0.995 0.833\n"," gate barrier 650 16 1 0.916 0.995 0.702\n"," left turn 650 19 0.248 0.416 0.336 0.225\n"," motorcycle 650 75 0.627 0.64 0.643 0.394\n"," obstacle 650 101 0.854 0.754 0.791 0.529\n"," pedestrian 650 13 0.627 0.846 0.743 0.499\n"," plant pot 650 43 0.941 0.953 0.961 0.595\n"," pole 650 66 0.672 0.682 0.701 0.472\n"," pothole 650 68 0.977 0.956 0.968 0.608\n"," puddle 650 59 0.696 0.78 0.796 0.508\n"," right turn 650 27 0.537 0.644 0.553 0.313\n"," roadblock 650 27 0.625 0.815 0.77 0.519\n"," stair 650 35 0.976 1 0.995 0.885\n"," street vendor 650 25 0.749 0.8 0.801 0.75\n"," tree 650 57 0.881 0.877 0.899 0.67\n"," zebra cross 650 104 0.823 0.923 0.909 0.63\n","Results saved to \u001b[1mruns/train/result_jetbot\u001b[0m\n"]}]},{"cell_type":"code","source":["!python /content/yolov5/detect.py --weights /content/yolov5/runs/train/result_jetbot/weights/best.pt --source /content/drive/MyDrive/vdo.mp4 # video"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"VSy0TXSTQg5i","executionInfo":{"status":"ok","timestamp":1706700538590,"user_tz":-540,"elapsed":38278,"user":{"displayName":"‍김호준(학부생-소프트웨어전공)","userId":"06251474112980864102"}},"outputId":"753051a1-db22-439f-cfb7-98529845ddb2"},"execution_count":21,"outputs":[{"output_type":"stream","name":"stdout","text":["\u001b[34m\u001b[1mdetect: \u001b[0mweights=['/content/yolov5/runs/train/result_jetbot/weights/best.pt'], source=/content/drive/MyDrive/vdo.mp4, data=data/coco128.yaml, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_csv=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False, vid_stride=1\n","YOLOv5 🚀 v7.0-282-g9cdbd1de Python-3.10.12 torch-2.1.0+cu121 CUDA:0 (Tesla T4, 15102MiB)\n","\n","Fusing layers... \n","YOLOv5x summary: 322 layers, 86314723 parameters, 0 gradients, 204.2 GFLOPs\n","video 1/1 (1/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 65.7ms\n","video 1/1 (2/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 41.0ms\n","video 1/1 (3/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 41.1ms\n","video 1/1 (4/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 garbage bin, 34.7ms\n","video 1/1 (5/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 garbage bin, 31.7ms\n","video 1/1 (6/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 garbage bin, 31.7ms\n","video 1/1 (7/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 garbage bin, 31.7ms\n","video 1/1 (8/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 garbage bin, 32.7ms\n","video 1/1 (9/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 garbage bin, 32.4ms\n","video 1/1 (10/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.7ms\n","video 1/1 (11/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.4ms\n","video 1/1 (12/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.2ms\n","video 1/1 (13/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (14/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.8ms\n","video 1/1 (15/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 car, 31.2ms\n","video 1/1 (16/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 car, 29.8ms\n","video 1/1 (17/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 car, 29.5ms\n","video 1/1 (18/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 car, 28.7ms\n","video 1/1 (19/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (20/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.5ms\n","video 1/1 (21/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.3ms\n","video 1/1 (22/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 car, 29.5ms\n","video 1/1 (23/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (24/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (25/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (26/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (27/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (28/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (29/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (30/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.5ms\n","video 1/1 (31/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (32/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.2ms\n","video 1/1 (33/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (34/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (35/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (36/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (37/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.2ms\n","video 1/1 (38/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (39/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.5ms\n","video 1/1 (40/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.5ms\n","video 1/1 (41/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (42/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (43/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.3ms\n","video 1/1 (44/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (45/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.3ms\n","video 1/1 (46/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (47/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (48/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (49/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (50/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.3ms\n","video 1/1 (51/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (52/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.4ms\n","video 1/1 (53/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.4ms\n","video 1/1 (54/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (55/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.6ms\n","video 1/1 (56/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (57/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (58/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (59/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.4ms\n","video 1/1 (60/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.6ms\n","video 1/1 (61/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (62/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.3ms\n","video 1/1 (63/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (64/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (65/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (66/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (67/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (68/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (69/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (70/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (71/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (72/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (73/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.9ms\n","video 1/1 (74/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (75/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.5ms\n","video 1/1 (76/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (77/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (78/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (79/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (80/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (81/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 30.1ms\n","video 1/1 (82/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 29.6ms\n","video 1/1 (83/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 30.1ms\n","video 1/1 (84/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (85/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 30.3ms\n","video 1/1 (86/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (87/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 31.2ms\n","video 1/1 (88/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 30.0ms\n","video 1/1 (89/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 29.3ms\n","video 1/1 (90/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 29.0ms\n","video 1/1 (91/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 29.9ms\n","video 1/1 (92/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 29.4ms\n","video 1/1 (93/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 29.1ms\n","video 1/1 (94/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 30.5ms\n","video 1/1 (95/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 29.9ms\n","video 1/1 (96/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 29.8ms\n","video 1/1 (97/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 29.7ms\n","video 1/1 (98/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 30.0ms\n","video 1/1 (99/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 29.8ms\n","video 1/1 (100/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 29.9ms\n","video 1/1 (101/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 30.1ms\n","video 1/1 (102/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 29.8ms\n","video 1/1 (103/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 29.3ms\n","video 1/1 (104/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 29.3ms\n","video 1/1 (105/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 30.7ms\n","video 1/1 (106/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 obstacle, 29.6ms\n","video 1/1 (107/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 29.8ms\n","video 1/1 (108/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 stair, 29.8ms\n","video 1/1 (109/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (110/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.5ms\n","video 1/1 (111/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (112/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (113/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 obstacle, 30.1ms\n","video 1/1 (114/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.1ms\n","video 1/1 (115/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 obstacle, 30.8ms\n","video 1/1 (116/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (117/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (118/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (119/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (120/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (121/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (122/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.1ms\n","video 1/1 (123/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (124/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (125/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (126/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (127/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (128/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (129/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (130/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (131/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (132/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.8ms\n","video 1/1 (133/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.1ms\n","video 1/1 (134/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (135/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (136/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (137/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (138/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (139/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (140/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (141/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (142/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.8ms\n","video 1/1 (143/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (144/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (145/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (146/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.5ms\n","video 1/1 (147/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.9ms\n","video 1/1 (148/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (149/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (150/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (151/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.8ms\n","video 1/1 (152/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.4ms\n","video 1/1 (153/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.8ms\n","video 1/1 (154/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.8ms\n","video 1/1 (155/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (156/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (157/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.8ms\n","video 1/1 (158/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.7ms\n","video 1/1 (159/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (160/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.3ms\n","video 1/1 (161/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (162/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (163/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (164/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (165/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (166/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (167/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.8ms\n","video 1/1 (168/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (169/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (170/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (171/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (172/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.1ms\n","video 1/1 (173/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (174/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 32.5ms\n","video 1/1 (175/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 33.8ms\n","video 1/1 (176/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.0ms\n","video 1/1 (177/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.3ms\n","video 1/1 (178/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.8ms\n","video 1/1 (179/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 28.6ms\n","video 1/1 (180/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 27.7ms\n","video 1/1 (181/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 29.1ms\n","video 1/1 (182/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (183/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (184/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (185/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (186/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.4ms\n","video 1/1 (187/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.1ms\n","video 1/1 (188/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (189/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (190/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.4ms\n","video 1/1 (191/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.1ms\n","video 1/1 (192/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (193/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (194/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.4ms\n","video 1/1 (195/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.7ms\n","video 1/1 (196/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.4ms\n","video 1/1 (197/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (198/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (199/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (200/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.1ms\n","video 1/1 (201/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 pothole, 28.8ms\n","video 1/1 (202/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.4ms\n","video 1/1 (203/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.1ms\n","video 1/1 (204/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.3ms\n","video 1/1 (205/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.0ms\n","video 1/1 (206/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.1ms\n","video 1/1 (207/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 29.3ms\n","video 1/1 (208/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 car, 1 door, 27.8ms\n","video 1/1 (209/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 car, 28.4ms\n","video 1/1 (210/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.0ms\n","video 1/1 (211/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.0ms\n","video 1/1 (212/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.4ms\n","video 1/1 (213/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 29.5ms\n","video 1/1 (214/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 pothole, 28.4ms\n","video 1/1 (215/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.3ms\n","video 1/1 (216/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 pothole, 29.2ms\n","video 1/1 (217/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 1 pothole, 28.5ms\n","video 1/1 (218/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 1 pothole, 28.5ms\n","video 1/1 (219/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 1 pothole, 28.2ms\n","video 1/1 (220/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 1 pothole, 29.7ms\n","video 1/1 (221/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 pothole, 28.0ms\n","video 1/1 (222/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 1 pothole, 29.0ms\n","video 1/1 (223/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 1 pothole, 28.7ms\n","video 1/1 (224/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 car, 1 door, 1 pothole, 28.7ms\n","video 1/1 (225/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 1 pothole, 29.2ms\n","video 1/1 (226/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 1 pothole, 28.6ms\n","video 1/1 (227/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 1 pothole, 28.0ms\n","video 1/1 (228/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 1 pothole, 29.0ms\n","video 1/1 (229/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 1 pothole, 29.0ms\n","video 1/1 (230/595) /content/drive/MyDrive/vdo.mp4: 640x384 2 doors, 28.3ms\n","video 1/1 (231/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 28.0ms\n","video 1/1 (232/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 28.1ms\n","video 1/1 (233/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 27.8ms\n","video 1/1 (234/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 27.7ms\n","video 1/1 (235/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 27.8ms\n","video 1/1 (236/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 30.4ms\n","video 1/1 (237/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 30.1ms\n","video 1/1 (238/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 29.9ms\n","video 1/1 (239/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 29.3ms\n","video 1/1 (240/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 29.3ms\n","video 1/1 (241/595) /content/drive/MyDrive/vdo.mp4: 640x384 2 doors, 29.5ms\n","video 1/1 (242/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 30.1ms\n","video 1/1 (243/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 31.0ms\n","video 1/1 (244/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 29.8ms\n","video 1/1 (245/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 street vendor, 30.2ms\n","video 1/1 (246/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 30.6ms\n","video 1/1 (247/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 31.2ms\n","video 1/1 (248/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 30.3ms\n","video 1/1 (249/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 29.8ms\n","video 1/1 (250/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (251/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.1ms\n","video 1/1 (252/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.4ms\n","video 1/1 (253/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (254/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (255/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (256/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (257/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 door, 30.4ms\n","video 1/1 (258/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.9ms\n","video 1/1 (259/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (260/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (261/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (262/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (263/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.1ms\n","video 1/1 (264/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.1ms\n","video 1/1 (265/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (266/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (267/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (268/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.8ms\n","video 1/1 (269/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.0ms\n","video 1/1 (270/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (271/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (272/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (273/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (274/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.8ms\n","video 1/1 (275/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.4ms\n","video 1/1 (276/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (277/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (278/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (279/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (280/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (281/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (282/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.7ms\n","video 1/1 (283/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 garbage bin, 30.2ms\n","video 1/1 (284/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 garbage bin, 31.0ms\n","video 1/1 (285/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 garbage bin, 30.2ms\n","video 1/1 (286/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 garbage bin, 29.9ms\n","video 1/1 (287/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 garbage bin, 30.1ms\n","video 1/1 (288/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 garbage bin, 30.7ms\n","video 1/1 (289/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 garbage bin, 30.2ms\n","video 1/1 (290/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 garbage bin, 29.7ms\n","video 1/1 (291/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (292/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (293/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.3ms\n","video 1/1 (294/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (295/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (296/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (297/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (298/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.3ms\n","video 1/1 (299/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (300/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (301/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (302/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.8ms\n","video 1/1 (303/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (304/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (305/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (306/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.8ms\n","video 1/1 (307/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (308/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.1ms\n","video 1/1 (309/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (310/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (311/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.8ms\n","video 1/1 (312/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (313/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (314/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.9ms\n","video 1/1 (315/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (316/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (317/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (318/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.5ms\n","video 1/1 (319/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.4ms\n","video 1/1 (320/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.5ms\n","video 1/1 (321/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.9ms\n","video 1/1 (322/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.0ms\n","video 1/1 (323/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.0ms\n","video 1/1 (324/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (325/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (326/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.1ms\n","video 1/1 (327/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (328/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (329/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (330/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (331/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (332/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.4ms\n","video 1/1 (333/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (334/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (335/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.8ms\n","video 1/1 (336/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (337/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.6ms\n","video 1/1 (338/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (339/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (340/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (341/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (342/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.3ms\n","video 1/1 (343/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (344/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (345/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.7ms\n","video 1/1 (346/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (347/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.8ms\n","video 1/1 (348/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.5ms\n","video 1/1 (349/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.9ms\n","video 1/1 (350/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (351/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (352/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (353/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.8ms\n","video 1/1 (354/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.2ms\n","video 1/1 (355/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (356/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (357/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (358/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (359/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.7ms\n","video 1/1 (360/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.2ms\n","video 1/1 (361/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (362/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (363/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (364/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (365/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.7ms\n","video 1/1 (366/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.7ms\n","video 1/1 (367/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.8ms\n","video 1/1 (368/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.2ms\n","video 1/1 (369/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.4ms\n","video 1/1 (370/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.4ms\n","video 1/1 (371/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (372/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (373/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (374/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.7ms\n","video 1/1 (375/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (376/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.6ms\n","video 1/1 (377/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (378/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (379/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (380/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (381/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (382/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.7ms\n","video 1/1 (383/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.3ms\n","video 1/1 (384/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (385/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (386/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (387/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.0ms\n","video 1/1 (388/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (389/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (390/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (391/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (392/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (393/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.8ms\n","video 1/1 (394/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (395/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (396/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.9ms\n","video 1/1 (397/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.1ms\n","video 1/1 (398/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (399/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (400/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (401/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.3ms\n","video 1/1 (402/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.6ms\n","video 1/1 (403/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.1ms\n","video 1/1 (404/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.7ms\n","video 1/1 (405/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (406/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.8ms\n","video 1/1 (407/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.7ms\n","video 1/1 (408/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (409/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (410/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (411/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (412/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.1ms\n","video 1/1 (413/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.1ms\n","video 1/1 (414/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (415/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.3ms\n","video 1/1 (416/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (417/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.6ms\n","video 1/1 (418/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (419/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.7ms\n","video 1/1 (420/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (421/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.1ms\n","video 1/1 (422/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.8ms\n","video 1/1 (423/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.7ms\n","video 1/1 (424/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.8ms\n","video 1/1 (425/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.3ms\n","video 1/1 (426/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.3ms\n","video 1/1 (427/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (428/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (429/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (430/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.8ms\n","video 1/1 (431/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.0ms\n","video 1/1 (432/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.4ms\n","video 1/1 (433/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (434/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (435/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (436/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.1ms\n","video 1/1 (437/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.0ms\n","video 1/1 (438/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (439/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (440/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.2ms\n","video 1/1 (441/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.5ms\n","video 1/1 (442/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (443/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (444/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (445/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.4ms\n","video 1/1 (446/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (447/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.8ms\n","video 1/1 (448/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.5ms\n","video 1/1 (449/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (450/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.8ms\n","video 1/1 (451/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.3ms\n","video 1/1 (452/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (453/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.4ms\n","video 1/1 (454/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (455/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.4ms\n","video 1/1 (456/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (457/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.0ms\n","video 1/1 (458/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (459/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.7ms\n","video 1/1 (460/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (461/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (462/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.5ms\n","video 1/1 (463/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.3ms\n","video 1/1 (464/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 36.1ms\n","video 1/1 (465/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.8ms\n","video 1/1 (466/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.7ms\n","video 1/1 (467/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.9ms\n","video 1/1 (468/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.8ms\n","video 1/1 (469/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.9ms\n","video 1/1 (470/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (471/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.5ms\n","video 1/1 (472/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (473/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (474/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (475/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (476/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (477/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (478/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.9ms\n","video 1/1 (479/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 27.8ms\n","video 1/1 (480/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.4ms\n","video 1/1 (481/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.1ms\n","video 1/1 (482/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.9ms\n","video 1/1 (483/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.2ms\n","video 1/1 (484/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (485/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.9ms\n","video 1/1 (486/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (487/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (488/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.8ms\n","video 1/1 (489/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (490/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.6ms\n","video 1/1 (491/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.8ms\n","video 1/1 (492/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (493/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.5ms\n","video 1/1 (494/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (495/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (496/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.7ms\n","video 1/1 (497/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.2ms\n","video 1/1 (498/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.5ms\n","video 1/1 (499/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.8ms\n","video 1/1 (500/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (501/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.5ms\n","video 1/1 (502/595) /content/drive/MyDrive/vdo.mp4: 640x384 1 garbage bin, 28.5ms\n","video 1/1 (503/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.3ms\n","video 1/1 (504/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.1ms\n","video 1/1 (505/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (506/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.0ms\n","video 1/1 (507/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 33.3ms\n","video 1/1 (508/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (509/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (510/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.0ms\n","video 1/1 (511/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (512/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.8ms\n","video 1/1 (513/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (514/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.1ms\n","video 1/1 (515/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (516/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.4ms\n","video 1/1 (517/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.8ms\n","video 1/1 (518/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.4ms\n","video 1/1 (519/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.4ms\n","video 1/1 (520/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (521/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.4ms\n","video 1/1 (522/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.4ms\n","video 1/1 (523/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (524/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.5ms\n","video 1/1 (525/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.6ms\n","video 1/1 (526/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.8ms\n","video 1/1 (527/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.1ms\n","video 1/1 (528/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.5ms\n","video 1/1 (529/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 32.2ms\n","video 1/1 (530/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.3ms\n","video 1/1 (531/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.0ms\n","video 1/1 (532/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.3ms\n","video 1/1 (533/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.7ms\n","video 1/1 (534/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.5ms\n","video 1/1 (535/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (536/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.9ms\n","video 1/1 (537/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.7ms\n","video 1/1 (538/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.4ms\n","video 1/1 (539/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.6ms\n","video 1/1 (540/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.9ms\n","video 1/1 (541/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.2ms\n","video 1/1 (542/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.6ms\n","video 1/1 (543/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (544/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (545/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.8ms\n","video 1/1 (546/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.9ms\n","video 1/1 (547/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (548/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.8ms\n","video 1/1 (549/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.3ms\n","video 1/1 (550/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.2ms\n","video 1/1 (551/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.5ms\n","video 1/1 (552/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (553/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.6ms\n","video 1/1 (554/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.1ms\n","video 1/1 (555/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.3ms\n","video 1/1 (556/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (557/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.4ms\n","video 1/1 (558/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.6ms\n","video 1/1 (559/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.5ms\n","video 1/1 (560/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.2ms\n","video 1/1 (561/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (562/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.7ms\n","video 1/1 (563/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.9ms\n","video 1/1 (564/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.5ms\n","video 1/1 (565/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.4ms\n","video 1/1 (566/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (567/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.2ms\n","video 1/1 (568/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.5ms\n","video 1/1 (569/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (570/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.3ms\n","video 1/1 (571/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.7ms\n","video 1/1 (572/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.8ms\n","video 1/1 (573/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.5ms\n","video 1/1 (574/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.4ms\n","video 1/1 (575/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.5ms\n","video 1/1 (576/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.1ms\n","video 1/1 (577/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (578/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.2ms\n","video 1/1 (579/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (580/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.8ms\n","video 1/1 (581/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (582/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.3ms\n","video 1/1 (583/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.9ms\n","video 1/1 (584/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.3ms\n","video 1/1 (585/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.1ms\n","video 1/1 (586/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.6ms\n","video 1/1 (587/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.5ms\n","video 1/1 (588/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.3ms\n","video 1/1 (589/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.0ms\n","video 1/1 (590/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 28.9ms\n","video 1/1 (591/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (592/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.2ms\n","video 1/1 (593/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 29.8ms\n","video 1/1 (594/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 30.6ms\n","video 1/1 (595/595) /content/drive/MyDrive/vdo.mp4: 640x384 (no detections), 31.3ms\n","Speed: 0.5ms pre-process, 30.2ms inference, 1.3ms NMS per image at shape (1, 3, 640, 640)\n","Results saved to \u001b[1mruns/detect/exp6\u001b[0m\n"]}]}]} \ No newline at end of file diff --git a/ai/depth_estimation_research/.DS_Store b/ai/depth_estimation_research/.DS_Store new file mode 100644 index 0000000000..5008ddfcf5 Binary files /dev/null and b/ai/depth_estimation_research/.DS_Store differ diff --git a/ai/depth_estimation_research/Real-time-depth-estimation.pdf b/ai/depth_estimation_research/Real-time-depth-estimation.pdf new file mode 100644 index 0000000000..d9ecbd4969 Binary files /dev/null and b/ai/depth_estimation_research/Real-time-depth-estimation.pdf differ diff --git a/backend/capstone2024/.gitignore b/backend/capstone2024/.gitignore new file mode 100644 index 0000000000..878b3e71f2 --- /dev/null +++ b/backend/capstone2024/.gitignore @@ -0,0 +1,38 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +/src/main/resources/config/application.properties +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/backend/capstone2024/build.gradle b/backend/capstone2024/build.gradle new file mode 100644 index 0000000000..a2cc7ceeeb --- /dev/null +++ b/backend/capstone2024/build.gradle @@ -0,0 +1,41 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.2.3' + id 'io.spring.dependency-management' version '1.1.4' +} + +group = 'com.example' +version = '0.0.1-SNAPSHOT' + +java { + sourceCompatibility = '21' +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-web' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'mysql:mysql-connector-java:8.0.28' + implementation 'com.h2database:h2' +} + +tasks.named('test') { + useJUnitPlatform() +} + +bootJar { + archiveFileName = 'capstone24.jar' +} diff --git a/backend/capstone2024/gradle/wrapper/gradle-wrapper.jar b/backend/capstone2024/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..d64cd49177 Binary files /dev/null and b/backend/capstone2024/gradle/wrapper/gradle-wrapper.jar differ diff --git a/backend/capstone2024/gradle/wrapper/gradle-wrapper.properties b/backend/capstone2024/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..1af9e0930b --- /dev/null +++ b/backend/capstone2024/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/backend/capstone2024/gradlew b/backend/capstone2024/gradlew new file mode 100644 index 0000000000..1aa94a4269 --- /dev/null +++ b/backend/capstone2024/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/backend/capstone2024/gradlew.bat b/backend/capstone2024/gradlew.bat new file mode 100644 index 0000000000..93e3f59f13 --- /dev/null +++ b/backend/capstone2024/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/backend/capstone2024/settings.gradle b/backend/capstone2024/settings.gradle new file mode 100644 index 0000000000..79b4187da1 --- /dev/null +++ b/backend/capstone2024/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'capstone' diff --git a/backend/capstone2024/src/main/java/com/example/capstone/CapstoneApplication.java b/backend/capstone2024/src/main/java/com/example/capstone/CapstoneApplication.java new file mode 100644 index 0000000000..ea6d21dc63 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/CapstoneApplication.java @@ -0,0 +1,14 @@ +package com.example.capstone; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CapstoneApplication { + + public static void main(String[] args) { + SpringApplication.run(CapstoneApplication.class, args); + } + + +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/controller/GeoCoding.java b/backend/capstone2024/src/main/java/com/example/capstone/api/controller/GeoCoding.java new file mode 100644 index 0000000000..aeb32aae58 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/controller/GeoCoding.java @@ -0,0 +1,105 @@ +package com.example.capstone.api.controller; + +import com.example.capstone.api.dto.*; +import com.example.capstone.api.service.GeoCodingService; +import com.example.capstone.api.service.PedestrianService; +import com.example.capstone.api.service.PoiService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class GeoCoding { + + private final GeoCodingService geoCodingService; + private final PedestrianService pedestrianService; + private final PoiService poiService; + @GetMapping("/address-to-coord") + public Coordinate testGPS(@RequestParam("address") String address){ + Coordinate coordinate; + coordinate = geoCodingService.requestGeoCoding(address).getCoordinateInfo().getCoordinate().get(0); + return coordinate; + } + + @GetMapping("/find-way") + public Properties checkPede(@RequestParam("startLat") String startLat + , @RequestParam("startLon") String startLon + , @RequestParam(value = "endAddress") String endAddress) throws Exception { + System.out.println("startLat = " + startLat); + System.out.println("startLon = " + startLon); + System.out.println("endAddress = " + endAddress); + Properties properties = new Properties(); + TmapPedestrianResponseDto tmapPedestrianResponseDto = pedestrianService.requestPedestrian(startLat, startLon, endAddress); + properties.setTotalDistance(tmapPedestrianResponseDto.getFeatures().getFirst().getProperties().getTotalDistance()); + properties.setTotalTime(tmapPedestrianResponseDto.getFeatures().getFirst().getProperties().getTotalTime()); + return properties; + } + + @GetMapping("/start-navi") + public Properties confirmPede(@RequestParam("startLat") String startLat + , @RequestParam("startLon") String startLon + , @RequestParam("endAddress") String endAddress + ,@RequestParam("uuid") String uuid) throws Exception { + System.out.println("startLat = " + startLat); + System.out.println("startLon = " + startLon); + System.out.println("endAddress = " + endAddress); + System.out.println("uuid = " + uuid); + TmapPedestrianResponseDto tmapPedestrianResponseDto = pedestrianService.startPedestrianNavi(startLat, startLon, endAddress, uuid); + Properties properties = new Properties(); + properties.setPointIndex(1); + properties.setDescription("경로 안내를 시작 합니다."+tmapPedestrianResponseDto.getFeatures().getFirst().getProperties().getDescription()); + return properties; + } + + @GetMapping("/poi") + public Poi poiTest(@RequestParam("address") String address){ + Poi testBody; + testBody = poiService.requestPoi(address).getSearchPoiInfo().getPois().getPoi().get(0); + return testBody; + } + + @GetMapping("/current-location") + public DistanceInfo currentLocation(@RequestParam("curLat") String curLat, + @RequestParam("curLon") String curLon, + @RequestParam("uuid") String uuid, + @RequestParam("pointIndex") int pointIndex, + @RequestParam("cnt") int cnt,@RequestParam("distance") int distance){ + System.out.println("-----------------current--------------"); + System.out.println("curLat = " + curLat); + System.out.println("curLon = " + curLon); + System.out.println("uuid = " + uuid); + System.out.println("pointIndex = " + pointIndex); + System.out.println("cnt = " + cnt); + + + return pedestrianService.currentLocationCheck(curLat, curLon, uuid, pointIndex,cnt,distance); + } + + @GetMapping("/direction") + public DirectionInfo direction(@RequestParam("curLat") String curLat, + @RequestParam("curLon") String curLon, + @RequestParam("uuid") String uuid, + @RequestParam("pointIndex") int pointIndex, + @RequestParam("curDir") String curDir){ + System.out.println("-----------------direction--------------"); + System.out.println("curLat = " + curLat); + System.out.println("curLon = " + curLon); + System.out.println("uuid = " + uuid); + System.out.println("pointIndex = " + pointIndex); + System.out.println("curDir = " + curDir); + + return pedestrianService.directionCheck(curLat, curLon, uuid, pointIndex,curDir); + } + + + @GetMapping("/cancel-navi") + public String cancelNavi(@RequestParam("uuid") String uuid){ + pedestrianService.cancelNavi(uuid); + + return uuid + " 관련 모든 경로 삭제 완료"; + } + + +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Coordinate.java b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Coordinate.java new file mode 100644 index 0000000000..315238aa09 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Coordinate.java @@ -0,0 +1,13 @@ +package com.example.capstone.api.dto; + +import lombok.Data; + +@Data +public class Coordinate { + //위도 + private String newLat; + //경도 + private String newLon; + + +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/dto/CoordinateInfo.java b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/CoordinateInfo.java new file mode 100644 index 0000000000..a6c30e7d56 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/CoordinateInfo.java @@ -0,0 +1,15 @@ +package com.example.capstone.api.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class CoordinateInfo { + + private String totalCount; + + @JsonProperty("coordinate") + private List coordinate; +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/dto/DirectionInfo.java b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/DirectionInfo.java new file mode 100644 index 0000000000..440b78cdbe --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/DirectionInfo.java @@ -0,0 +1,8 @@ +package com.example.capstone.api.dto; + +import lombok.Data; + +@Data +public class DirectionInfo { + private String dirMsg; +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/dto/DistanceInfo.java b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/DistanceInfo.java new file mode 100644 index 0000000000..f9ca889287 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/DistanceInfo.java @@ -0,0 +1,22 @@ +package com.example.capstone.api.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class DistanceInfo { + @JsonProperty("distance") + private String distance; + + private int pointIndex; + + private String description; + + private String lat; + private String lon; + + private String dir; + + private int cnt; + +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/dto/DistanceResponseDTO.java b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/DistanceResponseDTO.java new file mode 100644 index 0000000000..035bf9033a --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/DistanceResponseDTO.java @@ -0,0 +1,8 @@ +package com.example.capstone.api.dto; + +import lombok.Data; + +@Data +public class DistanceResponseDTO { + private DistanceInfo distanceInfo; +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Feature.java b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Feature.java new file mode 100644 index 0000000000..0607f7671e --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Feature.java @@ -0,0 +1,24 @@ +package com.example.capstone.api.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class Feature { + @JsonProperty("type") + private String type; + + /* + geometry.coordinate -> 노드별 위도, 경도 + */ + @JsonProperty("geometry") + private Geometry + geometry; + + /* + properties.pointIndex -> 목적지까지 순차적인 노드 번호 + */ + @JsonProperty("properties") + private Properties properties; + +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Geometry.java b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Geometry.java new file mode 100644 index 0000000000..e2cd827714 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Geometry.java @@ -0,0 +1,18 @@ +package com.example.capstone.api.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.List; + +@Data +@AllArgsConstructor +public class Geometry { + @JsonProperty("type") + private String type; + + @JsonProperty("coordinates") + private Object coordinates; + +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Poi.java b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Poi.java new file mode 100644 index 0000000000..0447a51563 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Poi.java @@ -0,0 +1,12 @@ +package com.example.capstone.api.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class Poi { + @JsonProperty("frontLat") + private String frontLat; + @JsonProperty("frontLon") + private String frontLon; +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Pois.java b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Pois.java new file mode 100644 index 0000000000..a59170f04c --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Pois.java @@ -0,0 +1,10 @@ +package com.example.capstone.api.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class Pois { + private List poi; +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Properties.java b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Properties.java new file mode 100644 index 0000000000..5e0a1fe535 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/Properties.java @@ -0,0 +1,13 @@ +package com.example.capstone.api.dto; + +import lombok.Data; + +@Data +public class Properties { + private Integer totalDistance; + private Integer totalTime; + private Integer index; + private Integer pointIndex; + private String name; + private String description; +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/dto/SearchPoiInfo.java b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/SearchPoiInfo.java new file mode 100644 index 0000000000..a3f8ca02c3 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/SearchPoiInfo.java @@ -0,0 +1,13 @@ +package com.example.capstone.api.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class SearchPoiInfo { + private int totalCount; + @JsonProperty("pois") + private Pois pois; +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/dto/TmapGeoCodingResponseDto.java b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/TmapGeoCodingResponseDto.java new file mode 100644 index 0000000000..a42a2dc956 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/TmapGeoCodingResponseDto.java @@ -0,0 +1,15 @@ +package com.example.capstone.api.dto; + +import lombok.*; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Setter +@ToString +public class TmapGeoCodingResponseDto { + + private CoordinateInfo coordinateInfo; + + +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/dto/TmapPedestrianResponseDto.java b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/TmapPedestrianResponseDto.java new file mode 100644 index 0000000000..22fec9f4a1 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/TmapPedestrianResponseDto.java @@ -0,0 +1,62 @@ +package com.example.capstone.api.dto; + +import com.example.capstone.api.model.Route; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Setter +@ToString +public class TmapPedestrianResponseDto { + @JsonProperty("type") + private String type; + @JsonProperty("features") + private List features; + + public TmapPedestrianResponseDto filteredPoint() { + final List features = new ArrayList<>(); + for (Feature feature : this.features) { + if (feature.getGeometry().getType().equalsIgnoreCase("point")) { + features.add(feature); + } + } + return new TmapPedestrianResponseDto( + this.type, + features + ); + } + + public List toEntities() { + TmapPedestrianResponseDto tmapPedestrianResponseDto = filteredPoint(); + List features = tmapPedestrianResponseDto.features; + + List routes = new ArrayList<>(); + + for (Feature feature : features) { + Properties properties = feature.getProperties(); + List coordinates = (List) feature.getGeometry().getCoordinates(); + Route route = new Route(); + + String lon = String.valueOf(coordinates.getFirst()); + route.setLon(lon); + + String lat = String.valueOf(coordinates.getLast()); + route.setLat(lat); + + Long pointIndex = Long.valueOf(properties.getPointIndex()); + route.setPointIndex(pointIndex); + + String description = properties.getDescription(); + route.setDescription(description); + + routes.add(route); + } + return routes; + } +} + diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/dto/TmapPoiResponseDto.java b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/TmapPoiResponseDto.java new file mode 100644 index 0000000000..104fccfb9e --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/dto/TmapPoiResponseDto.java @@ -0,0 +1,12 @@ +package com.example.capstone.api.dto; + +import lombok.*; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Setter +@ToString +public class TmapPoiResponseDto { + private SearchPoiInfo searchPoiInfo; +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/model/Route.java b/backend/capstone2024/src/main/java/com/example/capstone/api/model/Route.java new file mode 100644 index 0000000000..3807a4380f --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/model/Route.java @@ -0,0 +1,31 @@ +package com.example.capstone.api.model; + +import com.example.capstone.member.model.Member; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.sql.SQLTransactionRollbackException; + +@Getter +@Setter +@Entity +@NoArgsConstructor +public class Route { + + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private Long pointIndex; + + private String lat; + + private String lon; + + private String description; + + @ManyToOne + @JoinColumn(name = "member_uuid") + private Member member; + +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/repository/RouteRepository.java b/backend/capstone2024/src/main/java/com/example/capstone/api/repository/RouteRepository.java new file mode 100644 index 0000000000..efb4636780 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/repository/RouteRepository.java @@ -0,0 +1,22 @@ +package com.example.capstone.api.repository; + +import com.example.capstone.api.model.Route; +import com.example.capstone.member.model.Member; +import org.springframework.data.domain.Example; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.FluentQuery; +import org.springframework.data.repository.query.Param; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +public interface RouteRepository extends JpaRepository { + + List findByMemberUuid(final String uuid); + List findByMember(final Member member); + @Transactional(rollbackFor = Exception.class) + void deleteAllByMemberUuid(String uuid); +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/service/GeoCodingService.java b/backend/capstone2024/src/main/java/com/example/capstone/api/service/GeoCodingService.java new file mode 100644 index 0000000000..a3fa4e07fd --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/service/GeoCodingService.java @@ -0,0 +1,37 @@ +package com.example.capstone.api.service; + +import com.example.capstone.api.dto.TmapGeoCodingResponseDto; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; +import org.springframework.web.client.RestTemplate; + +import java.net.URI; + +@Service +@RequiredArgsConstructor +public class GeoCodingService { + + private final RestTemplate restTemplate; + private final UriBuilderService uriBuilderService; + private static final String APPKEY = "qnMdq4E5hK6Jiying7vO84rBBYBMqE0L8JibODZN"; + + public TmapGeoCodingResponseDto requestGeoCoding(String address) { + if (ObjectUtils.isEmpty(address)) return null; + + URI uri = uriBuilderService.buildUriGeoCodingByAddress(address); + + HttpHeaders headers = new HttpHeaders(); + headers.set("appKey", APPKEY); + + HttpEntity httpEntity = new HttpEntity<>(headers); + + //api 호출 + TmapGeoCodingResponseDto body = restTemplate.exchange(uri, HttpMethod.GET, httpEntity, TmapGeoCodingResponseDto.class).getBody(); + return body; + + } +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/service/PedestrianService.java b/backend/capstone2024/src/main/java/com/example/capstone/api/service/PedestrianService.java new file mode 100644 index 0000000000..8b51f3e161 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/service/PedestrianService.java @@ -0,0 +1,289 @@ +package com.example.capstone.api.service; + +import com.example.capstone.api.dto.*; +import com.example.capstone.api.model.Route; +import com.example.capstone.api.repository.RouteRepository; +import com.example.capstone.member.model.Member; +import com.example.capstone.member.repository.MemberRepository; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.client.RestTemplate; + +import java.net.URI; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + + +@Service +@RequiredArgsConstructor +public class PedestrianService { + private final RestTemplate restTemplate; + private final UriBuilderService uriBuilderService; + private final PoiService poiService; + private final ObjectMapper objectMapper; + private final RouteRepository routeRepository; + private final MemberRepository memberRepository; + + private static final String APPKEY = "qnMdq4E5hK6Jiying7vO84rBBYBMqE0L8JibODZN"; + + public TmapPedestrianResponseDto requestPedestrian(String startLat, String startLon, String endAddress) throws Exception { + + if (ObjectUtils.isEmpty(startLat) || ObjectUtils.isEmpty(startLon) || ObjectUtils.isEmpty(endAddress)) + return null; + //lon 경도 X + //lat 위도 Y + TmapPoiResponseDto tmapPoiResponseDto = poiService.requestPoi(endAddress); + + String endLat = tmapPoiResponseDto.getSearchPoiInfo().getPois().getPoi().getFirst().getFrontLat(); + String endLon = tmapPoiResponseDto.getSearchPoiInfo().getPois().getPoi().getFirst().getFrontLon(); + + + System.out.println("변환 완료"); + System.out.println("startLat = " + startLat); + System.out.println("startLon = " + startLon); + System.out.println("endLat = " + endLat); + System.out.println("endLon = " + endLon); + URI uri = uriBuilderService.buildUriPedestrianByCoord(); + + HttpHeaders headers = new HttpHeaders(); + headers.add("appKey", APPKEY); + + Map requestBody = new HashMap<>(); + requestBody.put("startX", startLon); + requestBody.put("startY", startLat); + requestBody.put("endX", endLon); + requestBody.put("endY", endLat); + requestBody.put("reqCoordType", "WGS84GEO"); + requestBody.put("startName", "출발지"); + requestBody.put("endName", endAddress); + HttpEntity> entity = new HttpEntity<>(requestBody, headers); +// + String jsonBody = objectMapper.writeValueAsString(requestBody); + // 콘솔에 출력 + System.out.println("Request JSON Body: " + jsonBody); + + //api 호출 + + // API 호출 및 응답 받기 (String 형태로) + String rawResponse = restTemplate.exchange(uri, HttpMethod.POST, entity, String.class).getBody(); + + // 불법 문자 전처리 (예제: Null 문자 제거) + String cleanedResponse = rawResponse.replace("\u0000", ""); + + // 전처리된 응답을 DTO로 변환 + TmapPedestrianResponseDto responseDto = objectMapper.readValue( + cleanedResponse, TmapPedestrianResponseDto.class + ); + + + + + return responseDto; + } + + + public TmapPedestrianResponseDto startPedestrianNavi(String startLat, String startLon, String endAddress, String uuid) throws Exception { + if (ObjectUtils.isEmpty(startLat) || ObjectUtils.isEmpty(startLon) || ObjectUtils.isEmpty(endAddress) || ObjectUtils.isEmpty(uuid)) + return null; + //lon 경도 X + //lat 위도 Y + TmapPoiResponseDto tmapPoiResponseDto = poiService.requestPoi(endAddress); + + String endLat = tmapPoiResponseDto.getSearchPoiInfo().getPois().getPoi().getFirst().getFrontLat(); + String endLon = tmapPoiResponseDto.getSearchPoiInfo().getPois().getPoi().getFirst().getFrontLon(); + + + System.out.println("변환 완료"); + System.out.println("startLat = " + startLat); + System.out.println("startLon = " + startLon); + System.out.println("endLat = " + endLat); + System.out.println("endLon = " + endLon); + URI uri = uriBuilderService.buildUriPedestrianByCoord(); + + HttpHeaders headers = new HttpHeaders(); + headers.add("appKey", APPKEY); + + Map requestBody = new HashMap<>(); + requestBody.put("startX", startLon); + requestBody.put("startY", startLat); + requestBody.put("endX", endLon); + requestBody.put("endY", endLat); + requestBody.put("reqCoordType", "WGS84GEO"); + requestBody.put("startName", "출발지"); + requestBody.put("endName", endAddress); + HttpEntity> entity = new HttpEntity<>(requestBody, headers); +// + // 콘솔에 출력 + String jsonBody = objectMapper.writeValueAsString(requestBody); + System.out.println("Request JSON Body: " + jsonBody); + + + // API 호출 및 응답 받기 (String 형태로) + String rawResponse = restTemplate.exchange(uri, HttpMethod.POST, entity, String.class).getBody(); + + // 불법 문자 전처리 (예제: Null 문자 제거) + String cleanedResponse = rawResponse.replace("\u0000", ""); + + // 전처리된 응답을 DTO로 변환 + TmapPedestrianResponseDto responseDto = objectMapper.readValue(cleanedResponse, TmapPedestrianResponseDto.class) + .filteredPoint(); + System.out.println(); + List entities = responseDto.toEntities(); + + Member member = memberRepository.findByUuid(uuid).getFirst(); + for (Route e : entities) { + e.setMember(member); + } + routeRepository.saveAll(entities); + return responseDto; + } + + public DistanceInfo currentLocationCheck(String curLat, String curLon, + String uuid, int pointIndex, int cnt, int distance){ + + List path = routeRepository.findByMemberUuid(uuid); + String nextLon = path.get(pointIndex).getLon(); + String nextLat = path.get(pointIndex).getLat(); + + + + + URI uri = uriBuilderService.buildUriDistanceInfo(curLon, curLat, nextLon, nextLat); + HttpHeaders headers = new HttpHeaders(); + headers.set("appKey", APPKEY); + + HttpEntity httpEntity = new HttpEntity<>(headers); + + //api 호출 + DistanceResponseDTO body = restTemplate.exchange(uri, HttpMethod.GET, httpEntity, DistanceResponseDTO.class).getBody(); + + DistanceInfo info = new DistanceInfo(); + int dist = Integer.parseInt(body.getDistanceInfo().getDistance()); + if (dist > distance) + cnt++; + + + + if (dist <= 5){ + info.setDistance(String.valueOf(dist)); + info.setPointIndex(pointIndex+1); + info.setCnt(cnt); + info.setLat(nextLat); + info.setLon(nextLon); + if(pointIndex == path.size()-1){ + info.setDescription("도착"); + System.out.println("dist = " + dist); + System.out.println("path 최대 인덱스 = " + (path.size()-1)); + } + else { + info.setDescription(path.get(pointIndex).getDescription()); + System.out.println("dist = " + dist); + System.out.println("path 최대 인덱스 = " + (path.size()-1)); + } + + return info; + } + else { + info.setDistance(String.valueOf(dist)); + info.setPointIndex(pointIndex); + if (cnt >= 4) { + info.setDescription("재탐색"); + info.setCnt(0); + } + else { + info.setCnt(cnt); + info.setDescription("이동중"); + } + info.setLat(nextLat); + info.setLon(nextLon); + + System.out.println("dist = " + dist); + System.out.println("path 최대 인덱스 = " + (path.size()-1)); + return info; + } + + } + public DirectionInfo directionCheck(String curLat, String curLon, + String uuid, int pointIndex, String curDir){ + + List path = routeRepository.findByMemberUuid(uuid); + String nextLon = path.get(pointIndex).getLon(); + String nextLat = path.get(pointIndex).getLat(); + //방향 계산 + + double startLatDouble = Double.parseDouble(curLat); + double startLonDouble = Double.parseDouble(curLon); + double endLatDouble = Double.parseDouble(nextLat); + double endLonDouble = Double.parseDouble(nextLon); + + double lat1 = Math.toRadians(startLatDouble); + double lon1 = Math.toRadians(startLonDouble); + double lat2 = Math.toRadians(endLatDouble); + double lon2 = Math.toRadians(endLonDouble); + + double dLon = lon2 - lon1; + + double x = Math.cos(lat2) * Math.sin(dLon); + double y = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon); + + double initialBearing = Math.atan2(x, y); + + // Convert bearing from radians to degrees + initialBearing = Math.toDegrees(initialBearing); + initialBearing = (initialBearing + 360) % 360; + + // Convert to 45 degree compass directions + String[] compassDirections = {"N", "E", "S", "W"}; + int index = (int) Math.round(initialBearing / 90) % 4; + + String targetDir = compassDirections[index]; + + int currentIndex = -1; + int targetIndex = -1; + String dirMsg; + + for (int i = 0; i < compassDirections.length; i++) { + if (compassDirections[i].equals(curDir)) { + currentIndex = i; + } + if (compassDirections[i].equals(targetDir)) { + targetIndex = i; + } + } + if (currentIndex == -1 || targetIndex == -1) { + dirMsg = "방위 계산 오류"; + } + + + int difference = targetIndex - currentIndex; + if (difference < 0) { + difference += 4; + } + + if (difference == 0) { + dirMsg = "해당 방향으로 진행하세요"; + } else if (difference == 1) { + dirMsg = "오른쪽으로 몸을 돌리세요"; + } else if (difference == 2) { + dirMsg = "뒤로 돌리세요"; + } else { + dirMsg = "왼쪽으로 몸을 돌리세요"; + } + DirectionInfo dirInfo = new DirectionInfo(); + dirInfo.setDirMsg(dirMsg); + return dirInfo; + } + public void cancelNavi(String uuid){ + routeRepository.deleteAllByMemberUuid(uuid); + System.out.println("uuid = " + uuid + "삭제 중"); + } + +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/service/PoiService.java b/backend/capstone2024/src/main/java/com/example/capstone/api/service/PoiService.java new file mode 100644 index 0000000000..4d977e25a8 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/service/PoiService.java @@ -0,0 +1,40 @@ +package com.example.capstone.api.service; + +import com.example.capstone.api.dto.TmapGeoCodingResponseDto; +import com.example.capstone.api.dto.TmapPoiResponseDto; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; +import org.springframework.web.client.RestTemplate; + +import java.net.URI; + +@Service +@RequiredArgsConstructor +public class PoiService { + + private final RestTemplate restTemplate; + private final UriBuilderService uriBuilderService; + + private static final String APPKEY = "qnMdq4E5hK6Jiying7vO84rBBYBMqE0L8JibODZN"; + + public TmapPoiResponseDto requestPoi(String address) { + if (ObjectUtils.isEmpty(address)) return null; + + URI uri = uriBuilderService.buildUriPoiByCoord(address); + + HttpHeaders headers = new HttpHeaders(); + headers.set("appKey", APPKEY); + + HttpEntity httpEntity = new HttpEntity<>(headers); + + //api 호출 + + TmapPoiResponseDto body2 = restTemplate.exchange(uri, HttpMethod.GET, httpEntity, TmapPoiResponseDto.class).getBody(); + return body2; + } + +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/api/service/UriBuilderService.java b/backend/capstone2024/src/main/java/com/example/capstone/api/service/UriBuilderService.java new file mode 100644 index 0000000000..31329c00b3 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/api/service/UriBuilderService.java @@ -0,0 +1,64 @@ +package com.example.capstone.api.service; + +import org.springframework.stereotype.Service; +import org.springframework.web.util.UriComponentsBuilder; + +import java.net.URI; + +@Service +public class UriBuilderService { + + //좌표 변환 + private static final String TMAP_GEO_CODING_URL = "https://apis.openapi.sk.com/tmap/geo/fullAddrGeo"; + //보행자 경로 검색 + private static final String TMAP_PEDESTRIAN_URL = "https://apis.openapi.sk.com/tmap/routes/pedestrian"; + //POI 검색 + private static final String TMAP_POI_URL = "https://apis.openapi.sk.com/tmap/pois"; + // 두 좌표 간 직선 거리 계산 + private static final String TMAP_DISTANCE = "https://apis.openapi.sk.com/tmap/routes/distance"; + + public URI buildUriGeoCodingByAddress(String address) { + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(TMAP_GEO_CODING_URL); + uriBuilder.queryParam("coordType", "WGS84GEO"); + uriBuilder.queryParam("fullAddr", address); + uriBuilder.queryParam("addressFlag", "F00"); + + URI uri = uriBuilder.build().encode().toUri(); + System.out.println("uri = " + uri); + return uri; + } + + //출발지 좌표값, 목적지 좌표값, 출발지 도착지 지명 필요 + public URI buildUriPedestrianByCoord() { + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(TMAP_PEDESTRIAN_URL); + uriBuilder.queryParam("version", "1"); + URI uri = uriBuilder.build().encode().toUri(); + System.out.println("pede uri = " + uri); + return uri; + } + + public URI buildUriPoiByCoord(String address) { + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(TMAP_POI_URL) + .queryParam("version", "1") + .queryParam("searchKeyword", address) + .queryParam("resCoordType", "WGS84GEO") + .queryParam("reqCoordType", "WGS84GEO"); + URI uri = uriBuilder.build().encode().toUri(); + System.out.println("uri = " + uri); + return uri; + } + + public URI buildUriDistanceInfo(String startX, String startY, String endX, String endY){ + UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(TMAP_DISTANCE) + .queryParam("version","1") + .queryParam("startX",startX) + .queryParam("startY",startY) + .queryParam("endX",endX) + .queryParam("endY",endY); + URI uri = uriComponentsBuilder.build().encode().toUri(); + System.out.println("uri = " + uri); + return uri; + + + } +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/config/RestTemplateConfig.java b/backend/capstone2024/src/main/java/com/example/capstone/config/RestTemplateConfig.java new file mode 100644 index 0000000000..2fe9c1e124 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/config/RestTemplateConfig.java @@ -0,0 +1,14 @@ +package com.example.capstone.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class RestTemplateConfig { + + @Bean + public RestTemplate restTemplate(){ + return new RestTemplate(); + } +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/member/controller/MemberController.java b/backend/capstone2024/src/main/java/com/example/capstone/member/controller/MemberController.java new file mode 100644 index 0000000000..3d8426a641 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/member/controller/MemberController.java @@ -0,0 +1,84 @@ +package com.example.capstone.member.controller; + +import com.example.capstone.member.dto.FavoriteRequest; +import com.example.capstone.member.dto.FavoriteResponse; +import com.example.capstone.member.dto.MemberCheckResponse; +import com.example.capstone.member.model.Favorite; +import com.example.capstone.member.model.Member; +import com.example.capstone.member.repository.FavoriteRepository; +import com.example.capstone.member.repository.MemberRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import java.sql.Timestamp; +import java.util.List; + +@RestController +public class MemberController { + + @Autowired + private MemberRepository memberRepository; + + @Autowired + private FavoriteRepository favoriteRepository; + + @GetMapping("/checkMember") + public ResponseEntity checkMember(@RequestParam String uuid) { + System.out.println("UUID: " + uuid); + + List memberList = memberRepository.findByUuid(uuid); + if (!memberList.isEmpty()) { + Member member = memberList.getFirst(); + System.out.println(member.toString()); + + List favoriteList = favoriteRepository.findByMemberUuid(uuid); + if (!favoriteList.isEmpty()) { + System.out.println(favoriteList.toString()); + MemberCheckResponse response = new MemberCheckResponse(member, favoriteList); + return ResponseEntity.ok(response); + } else { + System.out.println("즐겨찾기 X"); + MemberCheckResponse response = new MemberCheckResponse(member, null); + return ResponseEntity.ok(response); + } + } else { + Member newMember = new Member(uuid, new Timestamp(System.currentTimeMillis())); + memberRepository.save(newMember); + System.out.println("member 추가"); + + MemberCheckResponse response = new MemberCheckResponse(newMember, null); + System.out.println("즐겨찾기 X"); + return ResponseEntity.ok(response); + } + } + @PostMapping("/addFavorite") + public ResponseEntity addFavorite( + @RequestBody FavoriteRequest favoriteRequest + ) { + System.out.println("UUID : " + favoriteRequest.getMemberUuid()); + System.out.println("즐겨찾기명 : " + favoriteRequest.getFavoriteName()); + System.out.println("도착지명 : " + favoriteRequest.getDestinationName()); + System.out.println("도착지좌표 : " + favoriteRequest.getDestinationCoordinates()); + + List memberList = memberRepository.findByUuid(favoriteRequest.getMemberUuid()); + if (memberList.isEmpty()) { + System.out.println("member X"); + return ResponseEntity.badRequest().body(new FavoriteResponse(null)); + } + + Member member = memberList.getFirst(); + + Favorite newFavorite = new Favorite(); + newFavorite.setMemberUuid(favoriteRequest.getMemberUuid()); + newFavorite.setFavoriteName(favoriteRequest.getFavoriteName()); + newFavorite.setDestinationName(favoriteRequest.getDestinationName()); + newFavorite.setDestinationCoordinates(favoriteRequest.getDestinationCoordinates()); + newFavorite.setCreatedAt(new Timestamp(System.currentTimeMillis())); + + favoriteRepository.save(newFavorite); + System.out.println("즐겨찾기 추가"); + + FavoriteResponse response = new FavoriteResponse(newFavorite); + return ResponseEntity.ok(response); + } +} \ No newline at end of file diff --git a/backend/capstone2024/src/main/java/com/example/capstone/member/dto/FavoriteRequest.java b/backend/capstone2024/src/main/java/com/example/capstone/member/dto/FavoriteRequest.java new file mode 100644 index 0000000000..dce0dd0cbb --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/member/dto/FavoriteRequest.java @@ -0,0 +1,11 @@ +package com.example.capstone.member.dto; + +import lombok.Data; + +@Data +public class FavoriteRequest { + private String memberUuid; + private String favoriteName; + private String destinationName; + private String destinationCoordinates; +} \ No newline at end of file diff --git a/backend/capstone2024/src/main/java/com/example/capstone/member/dto/FavoriteResponse.java b/backend/capstone2024/src/main/java/com/example/capstone/member/dto/FavoriteResponse.java new file mode 100644 index 0000000000..0a07b9a1cd --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/member/dto/FavoriteResponse.java @@ -0,0 +1,13 @@ +package com.example.capstone.member.dto; + +import com.example.capstone.member.model.Favorite; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class FavoriteResponse { + private Favorite favorite; +} \ No newline at end of file diff --git a/backend/capstone2024/src/main/java/com/example/capstone/member/dto/MemberCheckResponse.java b/backend/capstone2024/src/main/java/com/example/capstone/member/dto/MemberCheckResponse.java new file mode 100644 index 0000000000..321bc32b1e --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/member/dto/MemberCheckResponse.java @@ -0,0 +1,18 @@ +package com.example.capstone.member.dto; + +import com.example.capstone.member.model.Member; +import com.example.capstone.member.model.Favorite; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class MemberCheckResponse { + private Member member; + private List favorites; +} \ No newline at end of file diff --git "a/backend/capstone2024/src/main/java/com/example/capstone/member/member\353\212\224\354\227\254\352\270\260\354\227\220.txt" "b/backend/capstone2024/src/main/java/com/example/capstone/member/member\353\212\224\354\227\254\352\270\260\354\227\220.txt" new file mode 100644 index 0000000000..e69de29bb2 diff --git a/backend/capstone2024/src/main/java/com/example/capstone/member/model/Favorite.java b/backend/capstone2024/src/main/java/com/example/capstone/member/model/Favorite.java new file mode 100644 index 0000000000..e896cf51ff --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/member/model/Favorite.java @@ -0,0 +1,41 @@ +package com.example.capstone.member.model; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.Getter; +import lombok.Setter; + +import java.sql.Timestamp; + +@Setter +@Getter +@Entity +public class Favorite { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String memberUuid; + private String favoriteName; + private String destinationName; + private String destinationCoordinates; + private Timestamp createdAt; + + public Favorite() { + + } + + @Override + public String toString() { + return "Favorite{" + + "id=" + id + + ", memberUuid='" + memberUuid + '\'' + + ", favoriteName='" + favoriteName + '\'' + + ", destinationName='" + destinationName + '\'' + + ", destinationCoordinates='" + destinationCoordinates + '\'' + + ", createdAt=" + createdAt + + '}'; + } +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/member/model/Member.java b/backend/capstone2024/src/main/java/com/example/capstone/member/model/Member.java new file mode 100644 index 0000000000..641fc82bb3 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/member/model/Member.java @@ -0,0 +1,36 @@ +package com.example.capstone.member.model; + +import java.sql.Timestamp; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +@Entity +public class Member { + + @Id + private String uuid; + + @Column(name = "created_at") + private Timestamp createdAt; + + public Member() { + } + + public Member(String uuid, Timestamp createdAt) { + this.uuid = uuid; + this.createdAt = createdAt; + } + + @Override + public String toString() { + return "Member{" + + ", uuid='" + uuid + '\'' + + ", createdAt=" + createdAt + + '}'; + } + +} \ No newline at end of file diff --git a/backend/capstone2024/src/main/java/com/example/capstone/member/repository/FavoriteRepository.java b/backend/capstone2024/src/main/java/com/example/capstone/member/repository/FavoriteRepository.java new file mode 100644 index 0000000000..595ca5ead7 --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/member/repository/FavoriteRepository.java @@ -0,0 +1,9 @@ +package com.example.capstone.member.repository; + +import com.example.capstone.member.model.Favorite; +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; + +public interface FavoriteRepository extends JpaRepository { + List findByMemberUuid(String memberUuid); +} diff --git a/backend/capstone2024/src/main/java/com/example/capstone/member/repository/MemberRepository.java b/backend/capstone2024/src/main/java/com/example/capstone/member/repository/MemberRepository.java new file mode 100644 index 0000000000..48f79bb6bd --- /dev/null +++ b/backend/capstone2024/src/main/java/com/example/capstone/member/repository/MemberRepository.java @@ -0,0 +1,9 @@ +package com.example.capstone.member.repository; + +import com.example.capstone.member.model.Member; +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; + +public interface MemberRepository extends JpaRepository { + List findByUuid(String uuid); +} \ No newline at end of file diff --git a/backend/capstone2024/src/main/resources/application.properties b/backend/capstone2024/src/main/resources/application.properties new file mode 100644 index 0000000000..3db13ee0c2 --- /dev/null +++ b/backend/capstone2024/src/main/resources/application.properties @@ -0,0 +1,9 @@ +spring.datasource.url=jdbc:mysql://localhost:3306/capstone?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=UTF-8&serverTimezone=UTC +spring.datasource.username=yoon +spring.datasource.password=yoon1234! +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.show-sql=true +spring.jpa.properties.hibernate.format_sql=false +spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect +spring.jpa.hibernate.ddl-auto=update diff --git a/backend/capstone2024/src/test/java/com/example/capstone/CapstoneApplicationTests.java b/backend/capstone2024/src/test/java/com/example/capstone/CapstoneApplicationTests.java new file mode 100644 index 0000000000..586b4782b2 --- /dev/null +++ b/backend/capstone2024/src/test/java/com/example/capstone/CapstoneApplicationTests.java @@ -0,0 +1,13 @@ +package com.example.capstone; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +//@SpringBootTest +class CapstoneApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/backend/capstone2024/src/test/java/com/example/capstone/api/dto/TmapPedestrianResponseDtoTest.java b/backend/capstone2024/src/test/java/com/example/capstone/api/dto/TmapPedestrianResponseDtoTest.java new file mode 100644 index 0000000000..8d817336af --- /dev/null +++ b/backend/capstone2024/src/test/java/com/example/capstone/api/dto/TmapPedestrianResponseDtoTest.java @@ -0,0 +1,30 @@ +package com.example.capstone.api.dto; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class TmapPedestrianResponseDtoTest { + + @Test + @DisplayName("filteredPoint()를 호출하면 geometryType이 Point인 객체만 반환된다.") + void test01() { + Feature point1 = new Feature(); + point1.setGeometry(new Geometry("Point", null)); + Feature point2 = new Feature(); + point2.setGeometry(new Geometry("LineString", null)); + Feature point3 = new Feature(); + point3.setGeometry(new Geometry("아무 의미도 없는 값", null)); + Feature point4 = new Feature(); + point4.setGeometry(new Geometry("point", null)); + List points = List.of(point1, point2, point3, point4); + + TmapPedestrianResponseDto temp = new TmapPedestrianResponseDto("temp", points); + TmapPedestrianResponseDto result = temp.filteredPoint(); + Assertions.assertThat(result.getFeatures()).hasSize(2); + } +} \ No newline at end of file diff --git a/backend/capstone2024/src/test/java/com/example/capstone/api/repository/RouteRepositoryTest.java b/backend/capstone2024/src/test/java/com/example/capstone/api/repository/RouteRepositoryTest.java new file mode 100644 index 0000000000..6e34460ff4 --- /dev/null +++ b/backend/capstone2024/src/test/java/com/example/capstone/api/repository/RouteRepositoryTest.java @@ -0,0 +1,60 @@ +package com.example.capstone.api.repository; + +import com.example.capstone.api.model.Route; +import com.example.capstone.member.model.Member; +import com.example.capstone.member.repository.MemberRepository; +import jakarta.persistence.EntityManager; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.data.cassandra.DataCassandraTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +import javax.swing.text.html.parser.Entity; + +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +@DataJpaTest +class RouteRepositoryTest { + + @Autowired + private MemberRepository memberRepository; + + @Autowired + private RouteRepository routeRepository; + + @Autowired + private EntityManager em; + + @Test + void assert_notNull() { + assertNotNull(memberRepository); + assertNotNull(routeRepository); + } + + @Test + void assert_findByMemberUuid() { + Member member = new Member(); + member.setUuid("정회창"); + memberRepository.save(member); + Route route = new Route(); + route.setMember(member); + route.setPointIndex(68L); + routeRepository.save(route); + em.flush(); + em.clear(); + System.out.println("ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ"); + List byMemberUuid = routeRepository.findByMemberUuid( + member.getUuid() + ); + em.flush(); + em.clear(); + System.out.println("ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ"); + routeRepository.findByMember(member); + + System.out.println(); + } +} \ No newline at end of file diff --git a/backend/testtest.txt b/backend/testtest.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git "a/docs/EYE-U \341\204\206\341\205\242\341\204\202\341\205\262\341\204\213\341\205\245\341\206\257.pdf" "b/docs/EYE-U \341\204\206\341\205\242\341\204\202\341\205\262\341\204\213\341\205\245\341\206\257.pdf" new file mode 100644 index 0000000000..306e2f63fd Binary files /dev/null and "b/docs/EYE-U \341\204\206\341\205\242\341\204\202\341\205\262\341\204\213\341\205\245\341\206\257.pdf" differ diff --git "a/docs/EYE-U \353\247\244\353\211\264\354\226\274.pdf" "b/docs/EYE-U \353\247\244\353\211\264\354\226\274.pdf" new file mode 100644 index 0000000000..306e2f63fd Binary files /dev/null and "b/docs/EYE-U \353\247\244\353\211\264\354\226\274.pdf" differ diff --git "a/docs/\341\204\211\341\205\256\341\204\222\341\205\242\341\206\274\341\204\200\341\205\247\341\206\257\341\204\200\341\205\252\341\204\207\341\205\251\341\204\200\341\205\251\341\204\211\341\205\245-\341\204\200\341\205\242\341\206\250\341\204\216\341\205\246\341\204\220\341\205\241\341\206\267\341\204\214\341\205\265\341\204\205\341\205\263\341\206\257 \341\204\222\341\205\252\341\206\257\341\204\213\341\205\255\341\206\274\341\204\222\341\205\241\341\206\253 \341\204\211\341\205\265\341\204\200\341\205\241\341\206\250\341\204\214\341\205\241\341\206\274\341\204\213\341\205\242\341\204\213\341\205\265\341\206\253\341\204\213\341\205\255\341\206\274 \341\204\207\341\205\251\341\204\222\341\205\242\341\206\274 \341\204\207\341\205\251\341\204\214\341\205\251 \341\204\213\341\205\242\341\206\270.pdf" "b/docs/\341\204\211\341\205\256\341\204\222\341\205\242\341\206\274\341\204\200\341\205\247\341\206\257\341\204\200\341\205\252\341\204\207\341\205\251\341\204\200\341\205\251\341\204\211\341\205\245-\341\204\200\341\205\242\341\206\250\341\204\216\341\205\246\341\204\220\341\205\241\341\206\267\341\204\214\341\205\265\341\204\205\341\205\263\341\206\257 \341\204\222\341\205\252\341\206\257\341\204\213\341\205\255\341\206\274\341\204\222\341\205\241\341\206\253 \341\204\211\341\205\265\341\204\200\341\205\241\341\206\250\341\204\214\341\205\241\341\206\274\341\204\213\341\205\242\341\204\213\341\205\265\341\206\253\341\204\213\341\205\255\341\206\274 \341\204\207\341\205\251\341\204\222\341\205\242\341\206\274 \341\204\207\341\205\251\341\204\214\341\205\251 \341\204\213\341\205\242\341\206\270.pdf" new file mode 100644 index 0000000000..82d1c2f704 Binary files /dev/null and "b/docs/\341\204\211\341\205\256\341\204\222\341\205\242\341\206\274\341\204\200\341\205\247\341\206\257\341\204\200\341\205\252\341\204\207\341\205\251\341\204\200\341\205\251\341\204\211\341\205\245-\341\204\200\341\205\242\341\206\250\341\204\216\341\205\246\341\204\220\341\205\241\341\206\267\341\204\214\341\205\265\341\204\205\341\205\263\341\206\257 \341\204\222\341\205\252\341\206\257\341\204\213\341\205\255\341\206\274\341\204\222\341\205\241\341\206\253 \341\204\211\341\205\265\341\204\200\341\205\241\341\206\250\341\204\214\341\205\241\341\206\274\341\204\213\341\205\242\341\204\213\341\205\265\341\206\253\341\204\213\341\205\255\341\206\274 \341\204\207\341\205\251\341\204\222\341\205\242\341\206\274 \341\204\207\341\205\251\341\204\214\341\205\251 \341\204\213\341\205\242\341\206\270.pdf" differ diff --git "a/docs/\354\210\230\355\226\211\352\262\260\352\263\274\353\263\264\352\263\240\354\204\234-\352\260\235\354\262\264\355\203\220\354\247\200\353\245\274 \355\231\234\354\232\251\355\225\234 \354\213\234\352\260\201\354\236\245\354\225\240\354\235\270\354\232\251 \353\263\264\355\226\211 \353\263\264\354\241\260 \354\225\261.pdf" "b/docs/\354\210\230\355\226\211\352\262\260\352\263\274\353\263\264\352\263\240\354\204\234-\352\260\235\354\262\264\355\203\220\354\247\200\353\245\274 \355\231\234\354\232\251\355\225\234 \354\213\234\352\260\201\354\236\245\354\225\240\354\235\270\354\232\251 \353\263\264\355\226\211 \353\263\264\354\241\260 \354\225\261.pdf" new file mode 100644 index 0000000000..82d1c2f704 Binary files /dev/null and "b/docs/\354\210\230\355\226\211\352\262\260\352\263\274\353\263\264\352\263\240\354\204\234-\352\260\235\354\262\264\355\203\220\354\247\200\353\245\274 \355\231\234\354\232\251\355\225\234 \354\213\234\352\260\201\354\236\245\354\225\240\354\235\270\354\232\251 \353\263\264\355\226\211 \353\263\264\354\241\260 \354\225\261.pdf" differ diff --git a/frontend/.DS_Store b/frontend/.DS_Store new file mode 100644 index 0000000000..15517fad3e Binary files /dev/null and b/frontend/.DS_Store differ diff --git a/frontend/flutter_vision-master/.gitignore b/frontend/flutter_vision-master/.gitignore new file mode 100644 index 0000000000..253e1941e4 --- /dev/null +++ b/frontend/flutter_vision-master/.gitignore @@ -0,0 +1,30 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ +.fvm \ No newline at end of file diff --git a/frontend/flutter_vision-master/.metadata b/frontend/flutter_vision-master/.metadata new file mode 100644 index 0000000000..a23172b921 --- /dev/null +++ b/frontend/flutter_vision-master/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 7e9793dee1b85a243edd0e06cb1658e98b077561 + channel: stable + +project_type: plugin diff --git a/frontend/flutter_vision-master/CHANGELOG.md b/frontend/flutter_vision-master/CHANGELOG.md new file mode 100644 index 0000000000..9a72ec5991 --- /dev/null +++ b/frontend/flutter_vision-master/CHANGELOG.md @@ -0,0 +1,31 @@ +## 1.1.4 +* Resolved the YoloV8 output bug and made updates to the latest version. Please find the latest release on the Ultralytics YOLOv8 0.181 GitHub repository +## 1.1.3 +* Release of segmentation feature via YOLOv8. +* Updated example code. +* Updated README. +## 1.1.2 +* GPU delegation error has been fixed. +* Coordinate representation of the box in documentation was fixed. +* Switching between models now are supported. +* Added quantization option for more efficient models at the cost of some precision. +## 1.1.1 +* Bounding box error has been fixed. +* Confidence scores for Yolov8 has been fixed. +## 1.1.0 +* loadOcrModel, ocrOnFrame, and closeOcrModel have been removed. Instead, Yolo and Tesseract operate independently of each other. +* Models no longer returns responseHandler as output. Instead, it returns a List>. +* The Tesseract model has been updated to version 5.0.0, resulting in improved accuracy. +* New methods have been added: loadYoloModel, yoloOnFrame, yoloOnImage, closeYoloModel, loadTesseractModel, tesseractOnImage, and closeTesseractModel. +* Support is now available for both Yolov5 and Yolov8. +* Resource management has been improved, and all models now operate in the background. + +## 1.0.0 +* Methods for Yolov5 now is available `(loadYoloModel, yoloOnFrame, closeYoloModel)`. +* Yolov5 and OCR model now is independent one to each other. + +## 0.0.2 +* `best` parameter has been removed + +## 0.0.1 +* Initial release. diff --git a/frontend/flutter_vision-master/LICENSE b/frontend/flutter_vision-master/LICENSE new file mode 100644 index 0000000000..8783b2f2d1 --- /dev/null +++ b/frontend/flutter_vision-master/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Yuri Vladimir Huallpa Vargas + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/frontend/flutter_vision-master/README.md b/frontend/flutter_vision-master/README.md new file mode 100644 index 0000000000..c7b86e1b31 --- /dev/null +++ b/frontend/flutter_vision-master/README.md @@ -0,0 +1,192 @@ +# flutter_vision + +A Flutter plugin for managing [Yolov5, Yolov8](https://github.com/ultralytics/ultralytics) and [Tesseract v5](https://tesseract-ocr.github.io/tessdoc/) accessing with TensorFlow Lite 2.x. Support object detection, segmentation and OCR on Android. iOS not updated, working in progress. + +# Installation +Add flutter_vision as a dependency in your pubspec.yaml file. + +## Android +In `android/app/build.gradle`, add the following setting in android block. + +```gradle + android{ + aaptOptions { + noCompress 'tflite' + noCompress 'lite' + } + } +``` +## iOS +Comming soon ... + +# Usage +## For YoloV5 and YoloV8 MODEL +1. Create a `assets` folder and place your labels file and model file in it. In `pubspec.yaml` add: + +``` + assets: + - assets/labels.txt + - assets/yolovx.tflite +``` + +2. Import the library: + +```dart +import 'package:flutter_vision/flutter_vision.dart'; +``` + +3. Initialized the flutter_vision library: + +```dart + FlutterVision vision = FlutterVision(); +``` + +4. Load the model and labels: +`modelVersion`: yolov5 or yolov8 or yolov8seg +```dart +await vision.loadYoloModel( + labels: 'assets/labelss.txt', + modelPath: 'assets/yolov5n.tflite', + modelVersion: "yolov5", + quantization: false, + numThreads: 1, + useGpu: false); +``` +### For camera live feed +5. Make your first detection: +`confThreshold` work with yolov5 other case it is omited. +> _Make use of [camera plugin](https://pub.dev/packages/camera)_ + +```dart +final result = await vision.yoloOnFrame( + bytesList: cameraImage.planes.map((plane) => plane.bytes).toList(), + imageHeight: cameraImage.height, + imageWidth: cameraImage.width, + iouThreshold: 0.4, + confThreshold: 0.4, + classThreshold: 0.5); +``` + +### For static image +5. Make your first detection or segmentation: + +```dart +final result = await vision.yoloOnImage( + bytesList: byte, + imageHeight: image.height, + imageWidth: image.width, + iouThreshold: 0.8, + confThreshold: 0.4, + classThreshold: 0.7); +``` + +6. Release resources: + +```dart +await vision.closeYoloModel(); +``` +## For Tesseract 5.0.0 MODEL +1. Create an `assets` folder, then create a `tessdata` directory and `tessdata_config.json` file and place them into it. +Download trained data for tesseract from [here](https://github.com/tesseract-ocr/tessdata) and place it into tessdata directory. Then, modifie tessdata_config.json as follow. +```json +{ + "files": [ + "spa.traineddata" + ] +} +``` + +2. In `pubspec.yaml` add: +``` +assets: + - assets/ + - assets/tessdata/ +``` +3. Import the library: + +```dart +import 'package:flutter_vision/flutter_vision.dart'; +``` + +4. Initialized the flutter_vision library: + +```dart + FlutterVision vision = FlutterVision(); +``` + +5. Load the model: + +```dart +await vision.loadTesseractModel( + args: { + 'psm': '11', + 'oem': '1', + 'preserve_interword_spaces': '1', + }, + language: 'spa', + ); +``` + +### For static image +6. Get Text from static image: + +```dart + final XFile? photo = await picker.pickImage(source: ImageSource.gallery); + if (photo != null) { + final result = await vision.tesseractOnImage(bytesList: (await photo.readAsBytes())); + } +``` + +7. Release resources: + +```dart +await vision.closeTesseractModel(); +``` +# About results +## For Yolo v5 or v8 in detection task +result is a `List>` where Map have the following keys: + + ``` dart + Map:{ + "box": [x1:left, y1:top, x2:right, y2:bottom, class_confidence] + "tag": String: detected class + } +``` + +## For YoloV8 in segmentation task +result is a `List>` where Map have the following keys: + + ``` dart + Map:{ + "box": [x1:left, y1:top, x2:right, y2:bottom, class_confidence] + "tag": String: detected class + "polygons": List>: [{x:coordx, y:coordy}] + } +``` + +## For Tesseract +result is a `List>` where Map have the following keys: + +```dart + Map:{ + "text": String + "word_conf": List:int + "mean_conf": int} +``` + +# Example +![Screenshot_2022-04-08-23-59-05-652_com vladih dni_scanner_example](https://user-images.githubusercontent.com/32783435/164163922-2eb7c8a3-8415-491f-883e-12cc87512efe.jpg) +Home +Detection +Segmentation + + +#
Contact
+ +For flutter_vision bug reports and feature requests please visit [GitHub Issues](https://github.com/vladiH/flutter_vision/issues) + +
+
+ + +
diff --git a/frontend/flutter_vision-master/analysis_options.yaml b/frontend/flutter_vision-master/analysis_options.yaml new file mode 100644 index 0000000000..a5744c1cfb --- /dev/null +++ b/frontend/flutter_vision-master/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/frontend/flutter_vision-master/android/.gitignore b/frontend/flutter_vision-master/android/.gitignore new file mode 100644 index 0000000000..c6cbe562a4 --- /dev/null +++ b/frontend/flutter_vision-master/android/.gitignore @@ -0,0 +1,8 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures diff --git a/frontend/flutter_vision-master/android/build.gradle b/frontend/flutter_vision-master/android/build.gradle new file mode 100644 index 0000000000..4e9e193b73 --- /dev/null +++ b/frontend/flutter_vision-master/android/build.gradle @@ -0,0 +1,66 @@ +group 'com.vladih.computer_vision.flutter_vision' +version '1.0' + +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.1.2' + } +} + +rootProject.allprojects { + repositories { + google() + mavenCentral() + flatDir{ + dirs project(":flutter_vision").file("libs") + } + maven { + url 'https://jitpack.io' + } + maven{ + name 'ossrh-snapshot' + url 'https://oss.sonatype.org/content/repositories/snapshots' + } + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 31 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + minSdkVersion 21 + } + aaptOptions { + noCompress 'tflite' + noCompress 'lite' + } + + buildFeatures{ + mlModelBinding true + } +} +dependencies{ + //implementation (files('libs/tesseract4android-release.aar')) + api(name:"tesseract4android-release", ext: "aar") + implementation 'com.github.vladiH:opencv-android:v1.0.0' + implementation 'org.tensorflow:tensorflow-lite:2.10.0' + implementation 'org.tensorflow:tensorflow-lite-api:2.10.0' + implementation 'org.tensorflow:tensorflow-lite-gpu:2.10.0' + implementation 'org.tensorflow:tensorflow-lite-gpu-api:2.10.0' + implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin:0.4.3' + implementation 'org.tensorflow:tensorflow-lite-support:0.4.3' + implementation 'org.tensorflow:tensorflow-lite-metadata:0.4.3' + implementation 'org.tensorflow:tensorflow-lite-select-tf-ops:2.11.0' +} \ No newline at end of file diff --git a/frontend/flutter_vision-master/android/gradle/wrapper/gradle-wrapper.jar b/frontend/flutter_vision-master/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..e708b1c023 Binary files /dev/null and b/frontend/flutter_vision-master/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/frontend/flutter_vision-master/android/gradle/wrapper/gradle-wrapper.properties b/frontend/flutter_vision-master/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..1a903ddfa5 --- /dev/null +++ b/frontend/flutter_vision-master/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Feb 22 11:31:00 CET 2023 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/frontend/flutter_vision-master/android/gradlew b/frontend/flutter_vision-master/android/gradlew new file mode 100644 index 0000000000..4f906e0c81 --- /dev/null +++ b/frontend/flutter_vision-master/android/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/frontend/flutter_vision-master/android/gradlew.bat b/frontend/flutter_vision-master/android/gradlew.bat new file mode 100644 index 0000000000..107acd32c4 --- /dev/null +++ b/frontend/flutter_vision-master/android/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/frontend/flutter_vision-master/android/libs/tesseract4android-release.aar b/frontend/flutter_vision-master/android/libs/tesseract4android-release.aar new file mode 100644 index 0000000000..42fe53b713 Binary files /dev/null and b/frontend/flutter_vision-master/android/libs/tesseract4android-release.aar differ diff --git a/frontend/flutter_vision-master/android/settings.gradle b/frontend/flutter_vision-master/android/settings.gradle new file mode 100644 index 0000000000..c434a6bcd5 --- /dev/null +++ b/frontend/flutter_vision-master/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "flutter_vision" \ No newline at end of file diff --git a/frontend/flutter_vision-master/android/src/main/AndroidManifest.xml b/frontend/flutter_vision-master/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..6854aa529f --- /dev/null +++ b/frontend/flutter_vision-master/android/src/main/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + diff --git a/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/FlutterVisionPlugin.java b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/FlutterVisionPlugin.java new file mode 100644 index 0000000000..5a71fa08af --- /dev/null +++ b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/FlutterVisionPlugin.java @@ -0,0 +1,387 @@ +package com.vladih.computer_vision.flutter_vision; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Matrix; + +import androidx.annotation.NonNull; + +import com.vladih.computer_vision.flutter_vision.models.Tesseract; +import com.vladih.computer_vision.flutter_vision.models.Yolo; +import com.vladih.computer_vision.flutter_vision.models.Yolov8; +import com.vladih.computer_vision.flutter_vision.models.Yolov5; +import com.vladih.computer_vision.flutter_vision.models.Yolov8Seg; +import com.vladih.computer_vision.flutter_vision.utils.utils; + +import org.opencv.android.OpenCVLoader; +import org.opencv.android.Utils; +import org.opencv.core.Mat; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import io.flutter.embedding.engine.plugins.FlutterPlugin; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.MethodChannel.MethodCallHandler; +import io.flutter.plugin.common.MethodChannel.Result; + +/** + * FlutterVisionPlugin + */ +public class FlutterVisionPlugin implements FlutterPlugin, MethodCallHandler { + private static final String CHANNEL_NAME = "flutter_vision"; + private MethodChannel methodChannel; + private Context context; + private FlutterAssets assets; + private Yolo yolo_model; + private Tesseract tesseract_model; + + private ExecutorService executor; + + private boolean isDetecting = false; + + private static ArrayList> empty = new ArrayList<>(); + + @Override + public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { + setupChannel(binding.getApplicationContext(), binding.getFlutterAssets(), binding.getBinaryMessenger()); + } + + @Override + public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { + try { + this.context = null; + this.methodChannel.setMethodCallHandler(null); + this.methodChannel = null; + this.assets = null; + close_tesseract(); + close_yolo(); + this.executor.shutdownNow(); + } catch (Exception e) { + if (!this.executor.isShutdown()) { + this.executor.shutdownNow(); + } +// System.out.println(e.getMessage()); + } + } + + private void setupChannel(Context context, FlutterAssets assets, BinaryMessenger messenger) { + OpenCVLoader.initDebug(); + this.assets = assets; + this.context = context; + this.methodChannel = new MethodChannel(messenger, CHANNEL_NAME); + this.methodChannel.setMethodCallHandler(this); + this.executor = Executors.newSingleThreadExecutor(); + } + + @Override + public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { + // Handle method calls from Flutter + if (call.method.equals("loadOcrModel")) { + try { + load_ocr_model((Map) call.arguments); + } catch (Exception e) { + result.error("100", "Error on load ocr components", e); + } + } else if (call.method.equals("ocrOnFrame")) { + ocr_on_frame((Map) call.arguments, result); + } else if (call.method.equals("closeOcrModel")) { + close_ocr_model(result); + } else if (call.method.equals("loadYoloModel")) { + try { + load_yolo_model((Map) call.arguments); + result.success("ok"); + } catch (Exception e) { + result.error("100", "Error on load Yolov5 model", e); + } + } else if (call.method.equals("yoloOnFrame")) { + yolo_on_frame((Map) call.arguments, result); + } else if (call.method.equals("yoloOnImage")) { + yolo_on_image((Map) call.arguments, result); + } else if (call.method.equals("closeYoloModel")) { + close_yolo_model(result); + } else if (call.method.equals("loadTesseractModel")) { + try { + load_tesseract_model((Map) call.arguments); + result.success("ok"); + } catch (Exception e) { + result.error("100", "Error on load Tesseract model", e); + } + } else if (call.method.equals("tesseractOnImage")) { + tesseract_on_image((Map) call.arguments, result); + } else if (call.method.equals("closeTesseractModel")) { + close_tesseract_model(result); + } else { + result.notImplemented(); + } + } + + private void load_ocr_model(Map args) throws Exception { + load_yolo_model(args); + load_tesseract_model(args); + } + + private void ocr_on_frame(Map args, Result result) { + try { + List image = (ArrayList) args.get("bytesList"); + int image_height = (int) args.get("image_height"); + int image_width = (int) args.get("image_width"); + float iou_threshold = (float) (double) (args.get("iou_threshold")); + float conf_threshold = (float) (double) (args.get("conf_threshold")); + float class_threshold = (float) (double) (args.get("class_threshold")); + List class_is_text = (List) args.get("class_is_text"); + Bitmap bitmap = utils.feedInputToBitmap(context.getApplicationContext(), image, image_height, image_width, 90); + int[] shape = yolo_model.getInputTensor().shape(); + ByteBuffer byteBuffer = utils.feedInputTensor(bitmap, shape[1], shape[2], image_width, image_height, 0, 255); + + List> yolo_results = yolo_model.detect_task(byteBuffer, image_height, image_width, iou_threshold, conf_threshold, class_threshold); + for (Map yolo_result : yolo_results) { + float[] box = (float[]) yolo_result.get("box"); + if (class_is_text.contains((int) box[5])) { + Bitmap crop = utils.crop_bitmap(bitmap, + box[0], box[1], box[2], box[3]); + //utils.getScreenshotBmp(crop, "crop"); + Bitmap tmp = crop.copy(crop.getConfig(), crop.isMutable()); + yolo_result.put("text", tesseract_model.predict_text(tmp)); + } else { + yolo_result.put("text", ""); + } + } + result.success(yolo_results); + } catch (Exception e) { + result.error("100", "Ocr error", e); + } + } + + private void close_ocr_model(Result result) { + try { + close_tesseract(); + close_yolo(); + result.success("OCR model closed succesfully"); + } catch (Exception e) { + result.error("100", "Fail closed ocr model", e); + } + } + + private void load_yolo_model(Map args) throws Exception { + final String model = this.assets.getAssetFilePathByName(args.get("model_path").toString()); + final Object is_asset_obj = args.get("is_asset"); + final boolean is_asset = is_asset_obj == null ? false : (boolean) is_asset_obj; + final int num_threads = (int) args.get("num_threads"); + final boolean quantization = (boolean) args.get("quantization"); + final boolean use_gpu = (boolean) args.get("use_gpu"); + final String label_path = this.assets.getAssetFilePathByName(args.get("label_path").toString()); + final int rotation = (int) args.get("rotation"); + final String version = args.get("model_version").toString(); + switch (version) { + case "yolov5": { + yolo_model = new Yolov5( + context, + model, + is_asset, + num_threads, + quantization, + use_gpu, + label_path, + rotation); + break; + } + case "yolov8": { + yolo_model = new Yolov8( + context, + model, + is_asset, + num_threads, + quantization, + use_gpu, + label_path, + rotation); + break; + } + + case "yolov8seg": { + yolo_model = new Yolov8Seg( + context, + model, + is_asset, + num_threads, + quantization, + use_gpu, + label_path, + rotation); + break; + } + default: { + throw new Exception("Model version must be yolov5, yolov8 or yolov8seg"); + } + } + yolo_model.initialize_model(); + } + + //https://www.baeldung.com/java-single-thread-executor-service + class DetectionTask implements Runnable { + // private static volatile DetectionTasks instance; + private Yolo yolo; + byte[] image; + + List frame; + int image_height; + int image_width; + float iou_threshold; + float conf_threshold; + float class_threshold; + + String typing; + private Result result; + + public DetectionTask(Yolo yolo, Map args, String typing, Result result) { + this.typing = typing; + this.yolo = yolo; + if (typing == "img") { + this.image = (byte[]) args.get("bytesList"); + } else { + this.frame = (ArrayList) args.get("bytesList"); + } + this.image_height = (int) args.get("image_height"); + this.image_width = (int) args.get("image_width"); + this.iou_threshold = (float) (double) (args.get("iou_threshold")); + this.conf_threshold = (float) (double) (args.get("conf_threshold")); + this.class_threshold = (float) (double) (args.get("class_threshold")); + this.result = result; + } + @Override + public void run() { + try { + Bitmap bitmap; + if (typing == "img") { + bitmap = BitmapFactory.decodeByteArray(image, 0, image.length); + } else { + //rotate image, because android take a photo rotating 90 degrees + bitmap = utils.feedInputToBitmap(context, frame, image_height, image_width, 90); + } + int[] shape = yolo.getInputTensor().shape(); + int src_width = bitmap.getWidth(); + int src_height = bitmap.getHeight(); + ByteBuffer byteBuffer = utils.feedInputTensor(bitmap, shape[1], shape[2], src_width, src_height, 0, 255); + List> detections = yolo.detect_task(byteBuffer, src_height, src_width, iou_threshold, conf_threshold, class_threshold); + isDetecting = false; + result.success(detections); + } catch (Exception e) { + result.error("100", "Detection Error", e); + } + } + } + + private void yolo_on_frame(Map args, Result result) { + try { + if (isDetecting) { + result.success(empty); + } else { + isDetecting = true; + DetectionTask detectionTask = new DetectionTask(yolo_model, args, "frame", result); + executor.submit(detectionTask); + } + } catch (Exception e) { + result.error("100", "Detection Error", e); + } + } + + private void yolo_on_image(Map args, Result result) { + try { + if (isDetecting) { + result.success(empty); + } else { + isDetecting = true; + DetectionTask detectionTask = new DetectionTask(yolo_model, args, "img", result); + executor.submit(detectionTask); + } + } catch (Exception e) { + result.error("100", "Detection Error", e); + } + } + + private void close_yolo_model(Result result) { + try { + close_yolo(); + result.success("Yolo model closed succesfully"); + } catch (Exception e) { + result.error("100", "Close_yolo_model error", e); + } + } + + private void load_tesseract_model(Map args) throws Exception { + final String tess_data = args.get("tess_data").toString(); + final Map arg = (Map) args.get("arg"); + final String language = args.get("language").toString(); + tesseract_model = new Tesseract(tess_data, arg, language); + tesseract_model.initialize_model(); + } + + class PredictionTask implements Runnable { + private Tesseract tesseract; + private Bitmap bitmap; + private Result result; + + public PredictionTask(Tesseract tesseract, Map args, Result result) { + byte[] image = (byte[]) args.get("bytesList"); + this.tesseract = tesseract; + this.bitmap = BitmapFactory.decodeByteArray(image, 0, image.length); + this.result = result; + } + + @Override + public void run() { + try { + Mat mat = utils.rgbBitmapToMatGray(bitmap); + double angle = utils.computeSkewAngle(mat.clone()); + mat = utils.deskew(mat, angle); + mat = utils.filterTextFromImage(mat); + bitmap = Bitmap.createBitmap(mat.width(), mat.height(), Bitmap.Config.ARGB_8888); + Utils.matToBitmap(mat, bitmap); +// utils.getScreenshotBmp(bitmap,"TESSEREACT"); + result.success(tesseract.predict_text(bitmap)); + } catch (Exception e) { + result.error("100", "Prediction text Error", e); + } + } + } + + private void tesseract_on_image(Map args, Result result) { + try { + PredictionTask predictionTask = new PredictionTask(tesseract_model, args, result); + executor.submit(predictionTask); + } catch (Exception e) { + result.error("100", "Prediction Error", e); + } + } + + private void close_tesseract_model(Result result) { + try { + close_tesseract(); + result.success("Tesseract model closed succesfully"); + } catch (Exception e) { + result.error("100", "close_tesseract_model error", e); + } + } + + private void close_tesseract(){ + if (tesseract_model != null) { + tesseract_model.close(); + tesseract_model = null; + } + } + + private void close_yolo(){ + if (yolo_model != null) { + yolo_model.close(); + yolo_model = null; + } + } +} diff --git a/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/models/Tesseract.java b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/models/Tesseract.java new file mode 100644 index 0000000000..9a7bc46875 --- /dev/null +++ b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/models/Tesseract.java @@ -0,0 +1,78 @@ +package com.vladih.computer_vision.flutter_vision.models; + +import android.graphics.Bitmap; + +import com.googlecode.tesseract.android.TessBaseAPI; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +public class Tesseract { + private TessBaseAPI interpreter; + private final int default_page_seg_mode = TessBaseAPI.PageSegMode.PSM_SINGLE_BLOCK; + private final String tess_data; + private final Map arg; + private final String language; + + public Tesseract(String tess_data, Map arg, String language) { + this.tess_data = tess_data; + this.arg = arg; + this.language = language; + } + public void close(){ + if (interpreter!=null){ + interpreter.clear(); + interpreter.recycle(); + } + } + public void initialize_model() throws Exception { + try { + if(interpreter==null){ + this.interpreter = new TessBaseAPI(); + if (!this.interpreter.init(this.tess_data, this.language)) { + // Error initializing Tesseract (wrong data path or language) + this.interpreter.recycle(); + throw new Exception("Cannot initialize Tesseract model"); + } + if(!this.arg.isEmpty()){ + for(Map.Entry entry:this.arg.entrySet()){ + interpreter.setVariable(entry.getKey(),entry.getValue()); + } + } + interpreter.setPageSegMode(this.default_page_seg_mode); + } + } + catch (Exception e){ + throw e; + } + } + + public Map predict_text(Bitmap bitmap) throws Exception { + try{ + this.interpreter.setImage(bitmap); + String result = this.interpreter.getUTF8Text(); + return out(result, interpreter.meanConfidence(), interpreter.wordConfidences()); + }catch (Exception e){ + throw new Exception(e.getMessage()); + }finally { + if(!bitmap.isRecycled()){ + bitmap.recycle(); + } + } + } + + protected Map out(String text, int mean, int[] word_conf){ + try { + Map result = new HashMap(); + result.put("text",text); + result.put("mean_conf", mean); + result.put("word_conf",word_conf); + return result; + }catch (Exception e){ + throw e; + } + } +} diff --git a/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/models/Yolo.java b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/models/Yolo.java new file mode 100644 index 0000000000..97d62548eb --- /dev/null +++ b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/models/Yolo.java @@ -0,0 +1,320 @@ +package com.vladih.computer_vision.flutter_vision.models; + +import static java.lang.Math.min; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.content.res.AssetManager; +import android.util.Log; + +import com.vladih.computer_vision.flutter_vision.utils.FeedInputTensorHelper; + +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.tensorflow.lite.Interpreter; +import org.tensorflow.lite.Tensor; +import org.tensorflow.lite.gpu.CompatibilityList; +import org.tensorflow.lite.gpu.GpuDelegate; +import org.tensorflow.lite.gpu.GpuDelegateFactory; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Array; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import io.flutter.embedding.engine.FlutterEngine; +import io.flutter.embedding.engine.plugins.FlutterPlugin; + +public class Yolo { + protected float[][][] output; + protected Interpreter interpreter; + protected Vector labels; + protected final Context context; + protected final String model_path; + protected final boolean is_assets; + protected final int num_threads; + protected final boolean quantization; + protected final boolean use_gpu; + protected final String label_path; + protected final int rotation; + + public Yolo(Context context, + String model_path, + boolean is_assets, + int num_threads, + boolean quantization, + boolean use_gpu, + String label_path, + int rotation) { + this.context = context; + this.model_path = model_path; + this.is_assets = is_assets; + this.num_threads = num_threads; + this.quantization = quantization; + this.use_gpu = use_gpu; + this.label_path = label_path; + this.rotation = rotation; + } + + // public Vector getLabels(){return this.labels;} + public Tensor getInputTensor() { + return this.interpreter.getInputTensor(0); + } + + @SuppressLint("SuspiciousIndentation") + public void initialize_model() throws Exception { + AssetManager asset_manager = null; + MappedByteBuffer buffer = null; + FileChannel file_channel = null; + FileInputStream input_stream = null; + + try { + if (is_assets) { + asset_manager = context.getAssets(); + AssetFileDescriptor file_descriptor = asset_manager.openFd(this.model_path); + input_stream = new FileInputStream(file_descriptor.getFileDescriptor()); + + file_channel = input_stream.getChannel(); + buffer = file_channel.map( + FileChannel.MapMode.READ_ONLY, file_descriptor.getStartOffset(), + file_descriptor.getLength() + ); + file_descriptor.close(); + } else { + input_stream = new FileInputStream(new File(this.model_path)); + file_channel = input_stream.getChannel(); + buffer = file_channel.map(FileChannel.MapMode.READ_ONLY, 0, file_channel.size()); + } + + Interpreter.Options interpreterOptions = new Interpreter.Options(); + try { + // Check if GPU support is available + CompatibilityList compatibilityList = new CompatibilityList(); + if (use_gpu && compatibilityList.isDelegateSupportedOnThisDevice()) { + GpuDelegateFactory.Options delegateOptions = compatibilityList.getBestOptionsForThisDevice(); + GpuDelegate gpuDelegate = new GpuDelegate(delegateOptions.setQuantizedModelsAllowed(this.quantization)); + interpreterOptions.addDelegate(gpuDelegate); + } else { + interpreterOptions.setNumThreads(num_threads); + } + // Create the interpreter + this.interpreter = new Interpreter(buffer, interpreterOptions); + } catch (Exception e) { + interpreterOptions = new Interpreter.Options(); + interpreterOptions.setNumThreads(num_threads); + // Create the interpreter + this.interpreter = new Interpreter(buffer, interpreterOptions); + } + this.interpreter.allocateTensors(); + this.labels = load_labels(asset_manager, label_path); + int[] shape = interpreter.getOutputTensor(0).shape();//3dimension + this.output = (float [][][]) Array.newInstance(float.class, shape); + } catch (Exception e) { + throw e; + } finally { + if (buffer != null) + buffer.clear(); + if (file_channel != null && file_channel.isOpen()) { + file_channel.close(); + input_stream.close(); + } + } + } + + protected Vector load_labels(AssetManager asset_manager, String label_path) throws Exception { + BufferedReader br = null; + try { + if (asset_manager != null) { + br = new BufferedReader(new InputStreamReader(asset_manager.open(label_path))); + } else { + br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(label_path)))); + } + String line; + Vector labels = new Vector<>(); + while ((line = br.readLine()) != null) { + labels.add(line); + } + return labels; + } catch (Exception e) { + throw new Exception(e.getMessage()); + } finally { + if (br != null) { + br.close(); + } + } + } + + public List> detect_task(ByteBuffer byteBuffer, + int source_height, + int source_width, + float iou_threshold, + float conf_threshold, float class_threshold) throws Exception { + try { + int[] input_shape = this.interpreter.getInputTensor(0).shape(); + this.interpreter.run(byteBuffer, this.output); + List boxes = filter_box(this.output, iou_threshold, conf_threshold, + class_threshold, input_shape[1], input_shape[2]); + boxes = restore_size(boxes, input_shape[1], input_shape[2], source_width, source_height); + return out(boxes, this.labels); + } catch (Exception e) { + throw e; + } finally { + byteBuffer.clear(); + } + } + + protected List filter_box(float[][][] model_outputs, float iou_threshold, + float conf_threshold, float class_threshold, float input_width, float input_height) { + try { + //model_outputs = [1,box+model_conf+class,detected_box] + List pre_box = new ArrayList<>(); + int conf_index = 4; + int class_index = 5; + int dimension = model_outputs[0][0].length; + int rows = model_outputs[0].length; + float x1, y1, x2, y2, conf; + int max_index = 0; + float max = 0f; + for (int i = 0; i < rows; i++) { + //convert xywh to xyxy + x1 = (model_outputs[0][i][0] - model_outputs[0][i][2] / 2f) * input_width; + y1 = (model_outputs[0][i][1] - model_outputs[0][i][3] / 2f) * input_height; + x2 = (model_outputs[0][i][0] + model_outputs[0][i][2] / 2f) * input_width; + y2 = (model_outputs[0][i][1] + model_outputs[0][i][3] / 2f) * input_height; + conf = model_outputs[0][i][conf_index]; + if (conf < conf_threshold) continue; + + max_index = class_index; + max = model_outputs[0][i][max_index]; + + for (int j = class_index + 1; j < dimension; j++) { + float current = model_outputs[0][i][j]; + if (current > max) { + max = current; + max_index = j; + } + } + if (max > class_threshold){ + float[] tmp = new float[6]; + tmp[0] = x1; + tmp[1] = y1; + tmp[2] = x2; + tmp[3] = y2; + tmp[4] = model_outputs[0][i][max_index]; + tmp[5] = (max_index - class_index) * 1f; + pre_box.add(tmp); + } + } + if (pre_box.isEmpty()) return new ArrayList<>(); + //for reverse orden, insteand of using .reversed method + Comparator compareValues = (v1, v2) -> Float.compare(v2[4], v1[4]); + //Collections.sort(pre_box,compareValues.reversed()); + Collections.sort(pre_box, compareValues); + return nms(pre_box, iou_threshold); + } catch (Exception e) { + throw e; + } + } + + protected static List nms(List boxes, float iou_threshold) { + try { + List filteredBoxes = new ArrayList<>(boxes); // Create a copy of the input list + + for (int i = 0; i < filteredBoxes.size(); i++) { + float[] box = filteredBoxes.get(i); + for (int j = i + 1; j < filteredBoxes.size(); j++) { + float[] next_box = filteredBoxes.get(j); + float x1 = Math.max(next_box[0], box[0]); + float y1 = Math.max(next_box[1], box[1]); + float x2 = Math.min(next_box[2], box[2]); + float y2 = Math.min(next_box[3], box[3]); + + float width = Math.max(0, x2 - x1); + float height = Math.max(0, y2 - y1); + + float intersection = width * height; + float union = (next_box[2] - next_box[0]) * (next_box[3] - next_box[1]) + + (box[2] - box[0]) * (box[3] - box[1]) - intersection; + float iou = intersection / union; + if (iou > iou_threshold) { + filteredBoxes.remove(j); + j--; + } + } + } + return filteredBoxes; + } catch (Exception e) { + Log.e("nms", e.getMessage()); + throw e; + } + } + + protected List restore_size(List nms, + int input_width, + int input_height, + int src_width, + int src_height) { + try { + //restore size after scaling, larger images + if (src_width > input_width || src_height > input_height) { + float gainx = src_width / (float) input_width; + float gainy = src_height / (float) input_height; + for (int i = 0; i < nms.size(); i++) { + nms.get(i)[0] = min(src_width, Math.max(nms.get(i)[0] * gainx, 0)); + nms.get(i)[1] = min(src_height, Math.max(nms.get(i)[1] * gainy, 0)); + nms.get(i)[2] = min(src_width, Math.max(nms.get(i)[2] * gainx, 0)); + nms.get(i)[3] = min(src_height, Math.max(nms.get(i)[3] * gainy, 0)); + } + //restore size after padding, smaller images + } else { + float padx = (src_width - input_width) / 2f; + float pady = (src_height - input_height) / 2f; + for (int i = 0; i < nms.size(); i++) { + nms.get(i)[0] = min(src_width, Math.max(nms.get(i)[0] + padx, 0)); + nms.get(i)[1] = min(src_height, Math.max(nms.get(i)[1] + pady, 0)); + nms.get(i)[2] = min(src_width, Math.max(nms.get(i)[2] + padx, 0)); + nms.get(i)[3] = min(src_height, Math.max(nms.get(i)[3] + pady, 0)); + } + } + return nms; + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + } + protected List> out(List yolo_result, Vector labels) { + try { + List> result = new ArrayList<>(); + //utils.getScreenshotBmp(bitmap, "current"); + for (float[] box : yolo_result) { + Map output = new HashMap<>(); + output.put("box", new float[]{box[0], box[1], box[2], box[3], box[4]}); //x1,y1,x2,y2,conf_class + output.put("tag", labels.get((int) box[5])); + result.add(output); + } + return result; + } catch (Exception e) { + throw e; + } + } + + public void close() { + try { + if (interpreter != null) + interpreter.close(); + } catch (Exception e) { + throw e; + } + } +} diff --git a/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/models/Yolov5.java b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/models/Yolov5.java new file mode 100644 index 0000000000..82ecdb5de5 --- /dev/null +++ b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/models/Yolov5.java @@ -0,0 +1,34 @@ +package com.vladih.computer_vision.flutter_vision.models; + +import static java.lang.Math.min; + +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.content.res.AssetManager; +import android.util.Log; + +import org.tensorflow.lite.Interpreter; +import org.tensorflow.lite.gpu.CompatibilityList; +import org.tensorflow.lite.gpu.GpuDelegate; + +import java.io.File; +import java.io.FileInputStream; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class Yolov5 extends Yolo{ + public Yolov5(Context context, + String model_path, + boolean is_assets, + int num_threads, + boolean quantization, + boolean use_gpu, + String label_path, + int rotation) { + super(context, model_path, is_assets, num_threads, quantization, use_gpu, label_path, rotation); + } +} diff --git a/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/models/Yolov8.java b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/models/Yolov8.java new file mode 100644 index 0000000000..cfe89c9cad --- /dev/null +++ b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/models/Yolov8.java @@ -0,0 +1,141 @@ +package com.vladih.computer_vision.flutter_vision.models; + +import static java.lang.Math.min; + +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.content.res.AssetManager; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.util.Log; + +import com.vladih.computer_vision.flutter_vision.utils.utils; + +import org.opencv.core.Core; +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.opencv.core.MatOfPoint; +import org.opencv.core.Point; +import org.opencv.imgproc.Imgproc; +import org.tensorflow.lite.Interpreter; +import org.tensorflow.lite.gpu.CompatibilityList; +import org.tensorflow.lite.gpu.GpuDelegate; +import org.tensorflow.lite.schema.Buffer; +import org.tensorflow.lite.schema.ReshapeOptions; +import org.tensorflow.lite.support.image.ImageProcessor; + +import java.io.File; +import java.io.FileInputStream; +import java.lang.reflect.Array; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.Vector; + +public class Yolov8 extends Yolo { + public Yolov8(Context context, + String model_path, + boolean is_assets, + int num_threads, + boolean quantization, + boolean use_gpu, + String label_path, + int rotation) { + super(context, model_path, is_assets, num_threads, quantization, use_gpu, label_path, rotation); + } + + @Override + public List> detect_task(ByteBuffer byteBuffer, + int source_height, + int source_width, + float iou_threshold, + float conf_threshold, + float class_threshold) throws Exception { + try { + int[] input_shape = this.interpreter.getInputTensor(0).shape(); + this.interpreter.run(byteBuffer, this.output); + //INFO: output from detection model is not normalized + List boxes = filter_box(this.output, iou_threshold, conf_threshold, + class_threshold, input_shape[1], input_shape[2]); + boxes = restore_size(boxes, input_shape[1], input_shape[2], source_width, source_height); + return out(boxes, this.labels); + } catch (Exception e) { + throw e; + } finally { + byteBuffer.clear(); + } + } + + @Override + protected List filter_box(float[][][] model_outputs, float iou_threshold, + float conf_threshold, float class_threshold, float input_width, float input_height) { + try { + //model_outputs = [1,box+class,detected_box] + List pre_box = new ArrayList<>(); + int class_index = 4; + int dimension = model_outputs[0][0].length; + int rows = model_outputs[0].length; + int max_index = 0; + float max = 0f; + for (int i = 0; i < dimension; i++) { + float x1 = (model_outputs[0][0][i] - model_outputs[0][2][i] / 2f)* input_width; + float y1 = (model_outputs[0][1][i] - model_outputs[0][3][i] / 2f)* input_height; + float x2 = (model_outputs[0][0][i] + model_outputs[0][2][i] / 2f)* input_width; + float y2 = (model_outputs[0][1][i] + model_outputs[0][3][i] / 2f)* input_height; + + max_index = class_index; + max = model_outputs[0][max_index][i]; + + for (int j = class_index + 1; j < rows; j++) { + float current = model_outputs[0][j][i]; + if (current > max) { + max = current; + max_index = j; + } + } + + if (max > class_threshold) { + float[] tmp = new float[6]; + tmp[0] = x1; + tmp[1] = y1; + tmp[2] = x2; + tmp[3] = y2; + tmp[4] = max; + tmp[5] = (max_index - class_index) * 1f; + pre_box.add(tmp); + } + } + if (pre_box.isEmpty()) return new ArrayList<>(); + //for reverse orden, insteand of using .reversed method + Comparator compareValues = (v1, v2) -> Float.compare(v2[4], v1[4]); + //Collections.sort(pre_box,compareValues.reversed()); + Collections.sort(pre_box, compareValues); + return nms(pre_box, iou_threshold); + } catch (Exception e) { + throw e; + } + } + + @Override + protected List> out(List yolo_result, Vector labels) { + try { + List> result = new ArrayList<>(); + for (float[] box : yolo_result) { + Map output = new HashMap<>(); + output.put("box", new float[]{box[0], box[1], box[2], box[3], box[4]}); //x1,y1,x2,y2,conf_class + output.put("tag", labels.get((int) box[5])); + result.add(output); + } + return result; + } catch (Exception e) { + throw e; + } + } +} diff --git a/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/models/Yolov8Seg.java b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/models/Yolov8Seg.java new file mode 100644 index 0000000000..b64f3e1bfe --- /dev/null +++ b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/models/Yolov8Seg.java @@ -0,0 +1,303 @@ +package com.vladih.computer_vision.flutter_vision.models; + +import static java.lang.Math.min; + +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.content.res.AssetManager; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.util.Log; + +import com.vladih.computer_vision.flutter_vision.utils.utils; + +import org.opencv.core.Core; +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.opencv.core.MatOfPoint; +import org.opencv.core.Point; +import org.opencv.imgproc.Imgproc; +import org.tensorflow.lite.Interpreter; +import org.tensorflow.lite.gpu.CompatibilityList; +import org.tensorflow.lite.gpu.GpuDelegate; +import org.tensorflow.lite.schema.Buffer; +import org.tensorflow.lite.schema.ReshapeOptions; +import org.tensorflow.lite.support.image.ImageProcessor; + +import java.io.File; +import java.io.FileInputStream; +import java.lang.reflect.Array; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.Vector; + +//https://dev.to/andreygermanov/how-to-implement-instance-segmentation-using-yolov8-neural-network-3if9 +//PAPER: https://openaccess.thecvf.com/content_ICCV_2019/papers/Bolya_YOLACT_Real-Time_Instance_Segmentation_ICCV_2019_paper.pdf +public class Yolov8Seg extends Yolo { + public Yolov8Seg(Context context, + String model_path, + boolean is_assets, + int num_threads, + boolean quantization, + boolean use_gpu, + String label_path, + int rotation) { + super(context, model_path, is_assets, num_threads, quantization, use_gpu, label_path, rotation); + } + + @Override + public List> detect_task(ByteBuffer byteBuffer, + int source_height, + int source_width, + float iou_threshold, + float conf_threshold, + float class_threshold) { + try { + if (has_multiple_output()) { + Map outputs = new HashMap<>(); + for (int i = 0; i < interpreter.getOutputTensorCount(); i++) { + int[] shape = interpreter.getOutputTensor(i).shape(); + outputs.put(i, Array.newInstance(float.class, shape)); + } + Object[] inputs = {byteBuffer}; + this.interpreter.runForMultipleInputsOutputs(inputs, outputs); + + int[] input_shape = interpreter.getInputTensor(0).shape(); // 1, 640, 640 + int[] output0_shape = interpreter.getOutputTensor(0).shape(); //1,116,2184 + int[] output1_shape = interpreter.getOutputTensor(1).shape(); //1,160,160,32 + + float[][][] output0 = (float[][][]) outputs.get(0); + + //seg_boxes = coordinates[4]+classes[x=84]+masks_weight[32] + //INFO: output from segment model return normalized values + List seg_boxes = filter_box(output0, + iou_threshold, conf_threshold, class_threshold, + input_shape[1], input_shape[2]); + + output0 = null; + + //it only restores the size of the boxes, nothing has been done with mask_weight + seg_boxes = restore_size(seg_boxes, input_shape[1], input_shape[2], + source_width, source_height); + + float[][][][] masks = (float[][][][]) outputs.get(1); + List seg_boxes_mask = new ArrayList<>(); + for (float[] mask_weight : seg_boxes) { + seg_boxes_mask.add(compute_mask(mask_weight, + masks[0], (float) 0.3, + output1_shape[1], output1_shape[2])); + } + masks = null; + List>> restore_seg_mask = restore_seg_mask_size(seg_boxes, + seg_boxes_mask, output1_shape[1], output1_shape[2], source_height, source_width + ); + return out_segmentation(seg_boxes, restore_seg_mask, this.labels); + } else { + throw new ExceptionInInitializerError("tflite model should have two outputs in segmentation mode"); + } + } catch (Exception e) { + throw e; + } finally { + byteBuffer.clear(); + } + } + + private int[] compute_mask(float[] mask_weight, + float[][][] masks_protos, + float seg_thresh, + int mask_height, + int mask_width) { + int prefix_box = 6; + int numMask = mask_weight.length - prefix_box; + int[] masks = new int[mask_height * mask_width]; + int index = 0; + // Set all pixels to either white (255) or black (0) + for (int h = 0; h < mask_height; h++) { + for (int w = 0; w < mask_width; w++) { + float sum = 0.0f; + for (int j = 0; j < numMask; j++) { + sum += mask_weight[j + prefix_box] * masks_protos[h][w][j]; + } + if (sigmoid(sum) > seg_thresh) { + masks[index++] = Color.WHITE; + } else { + masks[index++] = Color.BLACK; + } + } +// System.out.println(); + } +// Bitmap bitmap =Bitmap.createBitmap(masks, maskHeight, maskWidth, Bitmap.Config.ARGB_8888); +// utils.getScreenshotBmp(bitmap, UUID.randomUUID().toString()); + return masks; + } + + float sigmoid(float x) { + return (float) (1.0 / (1.0 + Math.exp(-x))); + } + + private List>> restore_seg_mask_size(List boxes, List seg_mask, + int mask_height, int mask_width, + int source_height, int source_width) { + Bitmap bitmap = null; + Bitmap crop = null; + try { + List>> polygons = new ArrayList<>(); + for (int i = 0; i < boxes.size(); i++) { + // Set the pixel data from the flattened array + bitmap = Bitmap.createBitmap(seg_mask.get(i), mask_width, mask_height, Bitmap.Config.ARGB_8888); +// String tag = UUID.randomUUID().toString(); +// utils.getScreenshotBmp(bitmap, tag+"0"); + crop = utils.crop_bitmap(bitmap, + min(mask_width, Math.max(boxes.get(i)[0] * mask_width / source_width, 0)), + min(mask_height, Math.max(boxes.get(i)[1] * mask_height / source_height, 0)), + min(mask_width, Math.max(boxes.get(i)[2] * mask_width / source_width, 0)), + min(mask_height, Math.max(boxes.get(i)[3] * mask_height / source_height, 0)) + ); +// utils.getScreenshotBmp(crop, tag+"1"); + List> crop_polygon = get_polygons_from_bitmap(crop, mask_height, + mask_width, source_height, source_width); + polygons.add(crop_polygon); + } + return polygons; + } catch (Exception e) { + throw e; + } finally { + if (bitmap != null) bitmap.recycle(); + if (crop != null) crop.recycle(); + } + } + + public static List> get_polygons_from_bitmap(Bitmap mask, + int mask_height, + int mask_width, + int source_height, + int source_width) { + Mat maskMat = utils.rgbBitmapToMatGray(mask); // Convert Bitmap to Mat + List contours = new ArrayList<>(); + Imgproc.findContours(maskMat, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE); + + MatOfPoint largestContour = null; + double largestArea = 0; + + for (MatOfPoint contour : contours) { + double area = Imgproc.contourArea(contour); + if (area > largestArea) { + largestArea = area; + largestContour = contour; + } + } + List polygon = new ArrayList<>(largestContour.toList()); +// List> polygons = new ArrayList<>(); +// for (MatOfPoint contour : contours) { +// List polygon = new ArrayList<>(); +// for (Point point : contour.toList()) { +// polygon.add(point); +// } +// polygons.add(polygon); +// } +// List>> converted_polygons = new ArrayList<>(); + +// for (List polygon : polygons) { + List> convertedPolygon = new ArrayList<>(); + for (Point point : polygon) { + Map pointMap = new HashMap<>(); + pointMap.put("x", point.x * source_width / mask_width); + pointMap.put("y", point.y * source_height / mask_height); + convertedPolygon.add(pointMap); + } +// converted_polygons.add(convertedPolygon); +// } +// return converted_polygons; + return convertedPolygon; + } + + private boolean has_multiple_output() { + return this.interpreter.getOutputTensorCount() > 1; + } + + @Override + protected List filter_box(float[][][] model_outputs, float iou_threshold, + float conf_threshold, float class_threshold, + float input_width, float input_height) { + try { + //model_outputs = [1,box+class+mask_weight,detected_box] + List pre_box = new ArrayList<>(); + int class_index = 4; + int dimension = model_outputs[0][0].length; + int rows = model_outputs[0].length; + int index_mask = rows - 32; + float[] mask_weight = new float[32]; + int max_index = 0; + float max = 0f; + for (int i = 0; i < dimension; i++) { + // Convertir xywh a xyxy y ajustar por el ancho y alto de entrada + float x1 = (model_outputs[0][0][i] - model_outputs[0][2][i] / 2f) * input_width; + float y1 = (model_outputs[0][1][i] - model_outputs[0][3][i] / 2f) * input_height; + float x2 = (model_outputs[0][0][i] + model_outputs[0][2][i] / 2f) * input_width; + float y2 = (model_outputs[0][1][i] + model_outputs[0][3][i] / 2f) * input_height; + + max_index = class_index; + max = model_outputs[0][max_index][i]; + + for (int j = class_index + 1; j < index_mask; j++) { + float current = model_outputs[0][j][i]; + if (current > max) { + max = current; + max_index = j; + } + } + + if (max > class_threshold) { + float[] tmp = new float[38]; + tmp[0] = x1; + tmp[1] = y1; + tmp[2] = x2; + tmp[3] = y2; + tmp[4] = max; + tmp[5] = (max_index - class_index) * 1f; + for (int j = index_mask; j < rows; j++) { + tmp[j - index_mask + 6] = model_outputs[0][j][i]; + } + pre_box.add(tmp); + } + } + if (pre_box.isEmpty()) return new ArrayList<>(); + //for reverse orden, insteand of using .reversed method + Comparator compareValues = (v1, v2) -> Float.compare(v2[4], v1[4]); + //Collections.sort(pre_box,compareValues.reversed()); + Collections.sort(pre_box, compareValues); + return nms(pre_box, iou_threshold); +// return nms_segmentation(pre_box, iou_threshold); + } catch (Exception e) { + throw e; + } + } + + //ignore out method of super class + protected List> out_segmentation(List yolo_result, + List>> polygons, + Vector labels) { + try { + List> result = new ArrayList<>(); + for (int i = 0; i < yolo_result.size(); i++) { + Map output = new HashMap<>(); + output.put("box", new float[]{yolo_result.get(i)[0], yolo_result.get(i)[1], + yolo_result.get(i)[2], yolo_result.get(i)[3], yolo_result.get(i)[4]}); //x1,y1,x2,y2,conf_class + output.put("polygons", polygons.get(i)); + output.put("tag", labels.get((int) yolo_result.get(i)[5])); + result.add(output); + } + return result; + } catch (Exception e) { + throw e; + } + } +} diff --git a/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/utils/FeedInputTensorHelper.java b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/utils/FeedInputTensorHelper.java new file mode 100644 index 0000000000..e940d4e624 --- /dev/null +++ b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/utils/FeedInputTensorHelper.java @@ -0,0 +1,72 @@ +package com.vladih.computer_vision.flutter_vision.utils; + +import android.graphics.Bitmap; + +import com.googlecode.leptonica.android.Scale; + +import org.tensorflow.lite.DataType; +import org.tensorflow.lite.support.common.ops.NormalizeOp; +import org.tensorflow.lite.support.image.ImageProcessor; +import org.tensorflow.lite.support.image.TensorImage; +import org.tensorflow.lite.support.image.ops.ResizeOp; +import org.tensorflow.lite.support.image.ops.ResizeWithCropOrPadOp; + +public class FeedInputTensorHelper { + private static FeedInputTensorHelper instance; + private TensorImage tensorImage; + private ImageProcessor downSizeImageProcessor; + private ImageProcessor upSizeImageProcessor; + + private int previus_width = 0; + private int previus_height = 0; + private FeedInputTensorHelper(int width, int height, float mean, float std) { + previus_width = width; + previus_height = height; + tensorImage = new TensorImage(DataType.FLOAT32); + downSizeImageProcessor = + new ImageProcessor.Builder() + // Resize using Bilinear or Nearest neighbour + .add(new ResizeOp(height, width, ResizeOp.ResizeMethod.BILINEAR)) + // Rotation counter-clockwise in 90 degree increments +// .add(new Rot90Op(rotateDegrees / 90)) + .add(new NormalizeOp(mean, std)) +// .add(new QuantizeOp(128.0, 1/128.0)) + .build(); + upSizeImageProcessor = + new ImageProcessor.Builder() + // Center crop the image to the largest square possible + .add(new ResizeWithCropOrPadOp(height, width)) + .add(new NormalizeOp(mean, std)) + .build(); + } + + public static synchronized FeedInputTensorHelper getInstance(int width, int height, float mean, float std) { + if (instance == null) { + instance = new FeedInputTensorHelper(width, height,mean, std); + }else{ + if (instance.previus_width!=width || instance.previus_height!=height){ + instance = new FeedInputTensorHelper(width, height,mean, std); + } + } + return instance; + } + + public static TensorImage getBytebufferFromBitmap(Bitmap bitmap, + int input_width, + int input_height, float mean, float std, String size_option) throws Exception { + try{ + //https://www.tensorflow.org/lite/inference_with_metadata/lite_support + FeedInputTensorHelper feedInputTensorHelper = getInstance(input_width, input_height, mean, std); + feedInputTensorHelper.tensorImage.load(bitmap); + if (size_option=="downsize"){ + return feedInputTensorHelper.downSizeImageProcessor.process(feedInputTensorHelper.tensorImage); + } + if (size_option=="upsize"){ + return feedInputTensorHelper.upSizeImageProcessor.process(feedInputTensorHelper.tensorImage); + } + throw new Exception("internal error, size_option no supported"); + }catch (Exception e){ + throw e; + } + } +} diff --git a/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/utils/RenderScriptHelper.java b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/utils/RenderScriptHelper.java new file mode 100644 index 0000000000..2cf0a18aff --- /dev/null +++ b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/utils/RenderScriptHelper.java @@ -0,0 +1,67 @@ +package com.vladih.computer_vision.flutter_vision.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.renderscript.Allocation; +import android.renderscript.Element; +import android.renderscript.RenderScript; +import android.renderscript.ScriptIntrinsicYuvToRGB; +import android.renderscript.Type; + +public class RenderScriptHelper { + private static RenderScriptHelper instance; + + private RenderScript rs; + private ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic; + private Type.Builder yuvType; + private Type.Builder rgbaType; + private Allocation in; + private Allocation out; + + private RenderScriptHelper(Context context) { + rs = RenderScript.create(context); + yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs)); + } + + public static synchronized RenderScriptHelper getInstance(Context context) { + if (instance == null) { + instance = new RenderScriptHelper(context); + } + return instance; + } + + public Allocation renderScriptNV21ToRGBA888(int width, int height, byte[] nv21) { + if (yuvType == null) { + yuvType = new Type.Builder(rs, Element.U8(rs)).setX(nv21.length); + } + if (rgbaType == null) { + rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height); + } + // Create input allocation for YUV data + if (in == null) { + in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT); + } + // Create output allocation for RGBA data + if (out == null) { + out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT); + } + + // Convert YUV to RGBA using RenderScript intrinsic + in.copyFrom(nv21); + yuvToRgbIntrinsic.setInput(in); + yuvToRgbIntrinsic.forEach(out); + return out; + } + + public static Bitmap getBitmapFromNV21(Context context, byte[] nv21, int width, int height) { + RenderScriptHelper rsHelper = getInstance(context); + //https://blog.minhazav.dev/how-to-convert-yuv-420-sp-android.media.Image-to-Bitmap-or-jpeg/ + Allocation allocation = rsHelper.renderScriptNV21ToRGBA888(width, height, nv21); + + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + allocation.copyTo(bitmap); + + return bitmap; + } +} \ No newline at end of file diff --git a/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/utils/utils.java b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/utils/utils.java new file mode 100644 index 0000000000..d629ac4fe5 --- /dev/null +++ b/frontend/flutter_vision-master/android/src/main/java/com/vladih/computer_vision/flutter_vision/utils/utils.java @@ -0,0 +1,345 @@ +package com.vladih.computer_vision.flutter_vision.utils; +import static java.lang.Math.min; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Matrix; +import android.os.Environment; + +import org.opencv.android.Utils; +import org.opencv.core.Core; +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.opencv.core.MatOfFloat; +import org.opencv.core.MatOfPoint; +import org.opencv.core.Point; +import org.opencv.core.Rect; +import org.opencv.core.Scalar; +import org.opencv.core.Size; +import org.opencv.imgproc.Imgproc; +import org.opencv.photo.Photo; +import org.tensorflow.lite.support.image.TensorImage; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class utils { + public static Bitmap crop_bitmap(Bitmap bitmap, float x1, float y1, float x2, float y2) { + try{ + final int x = Math.max((int)x1,0); + final int y = Math.max((int)y1,0); + final int width = Math.abs((int)(x2-x1)); + final int height = Math.abs((int)(y2-y1)); + return Bitmap.createBitmap(bitmap,x,y,width,height); + }catch (Exception e){ + throw e; + } + } + public static byte[] bitmap_to_byte(Bitmap bitmap){ + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG,100,stream); + return stream.toByteArray(); + } + public static Bitmap getScreenshotBmp(Bitmap bitmap, String name) { + FileOutputStream fileOutputStream = null; + + File path = Environment + .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); + + String uniqueID = name; + + File file = new File(path, uniqueID + ".jpg"); + try { + fileOutputStream = new FileOutputStream(file); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fileOutputStream); + + try { + fileOutputStream.flush(); + fileOutputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return bitmap; + } + //These code lines work well but is so slower, now rename as filterTextFromImage +// public static Mat image_preprocessing(Mat mat){ +// try { +// Photo.fastNlMeansDenoising(mat,mat, new MatOfFloat(7),3,21, Core.NORM_L1); +// Core.normalize(mat,mat, 0, 255, Core.NORM_MINMAX); +// Imgproc.GaussianBlur(mat, mat, new Size(5,5), 1); +// Imgproc.adaptiveThreshold(mat,mat,255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_BINARY,21,15); +// return mat; +// }catch (Exception e){ +// throw e; +// } +// } + //Accept gray Mat + public static Mat filterTextFromImage(Mat mat){ + try { + //find posibles box text + List rects = findRects(mat); + //join posibles box text that belong to same horizontal line + rects = mergeRects(rects); + //remove boxes which belong to another + rects = non_max_suppression(rects); + + Mat new_image = new Mat(mat.height(), mat.width(), CvType.CV_8UC1, new Scalar(255)); + for (Rect box : rects) { + try{ + //Todo: Still there are error to fix when image have black border ie. images, stains + //this errors are produced by findRects function, also text doesnt working when + // images has wave text + Mat crop = mat.submat(box); + Core.normalize(crop, crop, 0, 255, Core.NORM_MINMAX); + Imgproc.threshold(crop, crop, 0, 255, Imgproc.THRESH_BINARY + Imgproc.THRESH_OTSU); + Scalar meanScalar = Core.mean(crop); + double meanValue = meanScalar.val[0]; + if (meanValue<100){ + continue; + } + Mat roi = new_image.submat(new Rect(box.x, box.y, box.width, box.height)); + Core.bitwise_and(crop,roi,roi); + }catch (Exception e){ + System.err.println("Warning, vission text error filter"); + } +// crop.copyTo(roi); + } + return new_image; + }catch (Exception e){ + throw e; + } + } + public static Mat rgbBitmapToMatGray(Bitmap bitmap){ + Mat mat = new Mat(bitmap.getHeight(), bitmap.getWidth(), CvType.CV_8UC3); + Utils.bitmapToMat(bitmap,mat); + Imgproc.cvtColor(mat,mat, Imgproc.COLOR_RGB2GRAY); + return mat; + } + + public static List non_max_suppression(List boxes) { + // Sort the list of bounding boxes in ascending order based on their y-coordinates + Collections.sort(boxes, new Comparator() { + @Override + public int compare(Rect r1, Rect r2) { + return Integer.compare(r1.y, r2.y); + } + }); + + // Initialize the list of selected boxes + List selected_boxes = new ArrayList<>(); + + // Perform NMS + while (boxes.size() > 0) { + Rect current = boxes.get(0); + selected_boxes.add(current); + boxes.remove(0); + + List next_boxes = new ArrayList<>(); + for (Rect box : boxes) { + if (!contain(current, box) && (box.width/ box.height)>1) { + next_boxes.add(box); + } + } + boxes = next_boxes; + } + + return selected_boxes; + } + + public static boolean contain(Rect box1, Rect box2) { + // Calculate the coordinates of the intersection rectangle + int x1 = Math.max(box1.x, box2.x); + int y1 = Math.max(box1.y, box2.y); + int x2 = Math.min(box1.x+box1.width, box2.x+box2.width); + int y2 = Math.min(box1.y+box1.height, box2.y+box2.height); + int w = Math.max(0, x2 - x1); + int h = Math.max(0, y2 - y1); + + // Calculate the area of intersection rectangle + int intersection = w * h; + + // Calculate the area of both bounding boxes +// int area_box1 = box1.width * box1.height; + int area_box2 = box2.width * box2.height; + + return area_box2 == intersection; + } + public static List mergeRects(List rects){ + Collections.sort(rects, new Comparator() { + @Override + public int compare(Rect r1, Rect r2) { + return r1.y - r2.y; + } + }); + List mergedBoxes = new ArrayList<>(); + for (int i = 0; i < rects.size(); i++) { + Rect rect = rects.get(i); + if (mergedBoxes.isEmpty()) { + mergedBoxes.add(rect); + } else { + Rect prevRect = mergedBoxes.get(mergedBoxes.size()-1); + if (Math.abs(rect.y - prevRect.y) > prevRect.height * 0.5) { + mergedBoxes.add(rect); + } else { + if(rect.x - (prevRect.x + prevRect.width)> 0){ + mergedBoxes.add(rect); + } + else{ + int newX = Math.min(rect.x, prevRect.x); + int newY = Math.min(rect.y, prevRect.y); + int newW = Math.max(rect.x + rect.width, prevRect.x + prevRect.width) - newX; + int newH = Math.max(rect.y + rect.height, prevRect.y + prevRect.height) - newY; + mergedBoxes.set(mergedBoxes.size()-1, new Rect(newX, newY, newW, newH)); + } + } + } + } + return mergedBoxes; + } + public static List findRects(Mat image){ + Mat thresh = new Mat(); + //find countours in gray image + Imgproc.Canny(image, thresh, 50, 150, 3, false); + List contours = new ArrayList<>(); + Mat hierarchy = new Mat(); + Imgproc.findContours(thresh, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE); + List filteredContours = new ArrayList<>(); + double height = 0; + for (int i = 0; i < contours.size(); i++) { + Rect rect = Imgproc.boundingRect(contours.get(i)); + double area = rect.width * rect.height; + double aspectRatio = (double)rect.width / rect.height; + //remove rect that doesn't satisface this rules + if (area > 80 && aspectRatio > 0.4 && aspectRatio < 5) { + height += rect.height; + filteredContours.add(new Rect((int)Math.max(0, rect.x-rect.height/2), rect.y, (int)Math.min(image.width(),rect.width+rect.height), rect.height)); + } + } + //remove rects with large height than mean height + height = height / Math.sqrt(filteredContours.size()); + List rects = new ArrayList<>(); + for (int i = 0; i < filteredContours.size(); i++) { + Rect rect = filteredContours.get(i); + if (rect.height > height) continue; + rects.add(rect); + } + return rects; + } + public static Mat deskew(Mat image, double skewAngle) { + try { + Mat rotationMatrix = Imgproc.getRotationMatrix2D(new Point(image.width() / 2, image.height() / 2), skewAngle, 1); + Scalar borderValue = new Scalar(255); // white border value + // Crop the output image to remove border artifacts + Rect cropRect = new Rect(0, 0, image.width(), image.height()); +// System.out.println(image.size()); +// System.out.println(skewAngle); + Imgproc.warpAffine(image, image, rotationMatrix, image.size(), Imgproc.INTER_CUBIC + Imgproc.WARP_FILL_OUTLIERS, Core.BORDER_CONSTANT, borderValue); + image = image.submat(cropRect); + return image; + }catch (Exception e){ + throw e; + } + } + + //input:binary matrix + public static double computeSkewAngle(Mat image) { + try { + // Apply Canny edge detection to find the edges in the image + Imgproc.Canny(image, image, 50, 150, 3); + // Apply the Hough transform to find the lines in the image + Mat lines = new Mat(); + Imgproc.HoughLinesP(image, lines, 1, Math.PI / 180, 100, 100, 10); + + // Compute the average angle of the lines + double angle = 0.0; + int numLines = lines.cols(); + if (numLines > 0) { + // Find the longest line + double longestLineLength = -1; + Point[] longestLine = null; + for (int i = 0; i < lines.cols(); i++) { + double[] line = lines.get(0, i); + Point pt1 = new Point(line[0], line[1]); + Point pt2 = new Point(line[2], line[3]); + double length = Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2)); + if (length > longestLineLength) { + longestLineLength = length; + longestLine = new Point[] { pt1, pt2 }; + } + } + // Calculate angle between longest line and horizontal axis + double dx = longestLine[1].x - longestLine[0].x; + double dy = longestLine[1].y - longestLine[0].y; + angle = Math.atan2(dy, dx) * 180 / Math.PI; + } + // Convert the angle from radians to degrees and return it + return angle; + } catch (Exception e) { + throw e; + } + } + + + public static ByteBuffer feedInputTensor( + Bitmap bitmap, + int input_width, + int input_height, + int src_width, + int src_height, + float mean, + float std) throws Exception { + try { +// utils.getScreenshotBmp(bitmap, "antes"); + TensorImage tensorImage; + if (src_width > input_width || src_height > input_height) { + tensorImage= FeedInputTensorHelper.getBytebufferFromBitmap(bitmap, input_width, input_height, mean, std, "downsize"); + }else{ + tensorImage= FeedInputTensorHelper.getBytebufferFromBitmap(bitmap, input_width, input_height, mean, std, "upsize"); + } +// utils.getScreenshotBmp(tensorImage.getBitmap(), "despues"); + return tensorImage.getBuffer(); + }catch (Exception e){ + throw e; + + }finally { + assert bitmap != null; + if(!bitmap.isRecycled()){ + bitmap.recycle(); + } + } + } + public static Bitmap feedInputToBitmap(Context context, + List bytesList, + int imageHeight, + int imageWidth, + int rotation) throws Exception { + + int Yb = bytesList.get(0).length; + int Ub = bytesList.get(1).length ; + int Vb = bytesList.get(2).length ; + // Copy YUV data to plane byte + byte[] data = new byte[Yb+Ub+Vb]; + System.arraycopy(bytesList.get(0), 0, data, 0, Yb); + System.arraycopy(bytesList.get(2), 0, data, Yb, Ub); + System.arraycopy(bytesList.get(1), 0, data, Yb+Ub, Vb); + + Bitmap bitmapRaw = RenderScriptHelper.getBitmapFromNV21(context,data, imageWidth, imageHeight); +// utils.getScreenshotBmp(bitmapRaw, "NV21"); + Matrix matrix = new Matrix(); + matrix.postRotate(rotation); + bitmapRaw = Bitmap.createBitmap(bitmapRaw, 0, 0, bitmapRaw.getWidth(), bitmapRaw.getHeight(), matrix, true); + return bitmapRaw; + } +} diff --git a/frontend/flutter_vision-master/example/.gitignore b/frontend/flutter_vision-master/example/.gitignore new file mode 100644 index 0000000000..0fa6b675c0 --- /dev/null +++ b/frontend/flutter_vision-master/example/.gitignore @@ -0,0 +1,46 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/frontend/flutter_vision-master/example/.metadata b/frontend/flutter_vision-master/example/.metadata new file mode 100644 index 0000000000..5a023280af --- /dev/null +++ b/frontend/flutter_vision-master/example/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 7e9793dee1b85a243edd0e06cb1658e98b077561 + channel: stable + +project_type: app diff --git a/frontend/flutter_vision-master/example/README.md b/frontend/flutter_vision-master/example/README.md new file mode 100644 index 0000000000..30dcde6637 --- /dev/null +++ b/frontend/flutter_vision-master/example/README.md @@ -0,0 +1,16 @@ +# flutter_vision_example + +Demonstrates how to use the flutter_vision plugin. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/frontend/flutter_vision-master/example/analysis_options.yaml b/frontend/flutter_vision-master/example/analysis_options.yaml new file mode 100644 index 0000000000..61b6c4de17 --- /dev/null +++ b/frontend/flutter_vision-master/example/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/frontend/flutter_vision-master/example/android/.gitignore b/frontend/flutter_vision-master/example/android/.gitignore new file mode 100644 index 0000000000..6f568019d3 --- /dev/null +++ b/frontend/flutter_vision-master/example/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/frontend/flutter_vision-master/example/android/app/build.gradle b/frontend/flutter_vision-master/example/android/app/build.gradle new file mode 100644 index 0000000000..c0c4fa70b8 --- /dev/null +++ b/frontend/flutter_vision-master/example/android/app/build.gradle @@ -0,0 +1,56 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion flutter.compileSdkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.vladih.computer_vision.flutter_vision_example" + minSdkVersion localProperties.getProperty('flutter.minSdkVersion').toInteger() + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} diff --git a/frontend/flutter_vision-master/example/android/app/src/debug/AndroidManifest.xml b/frontend/flutter_vision-master/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000000..8117cc51fe --- /dev/null +++ b/frontend/flutter_vision-master/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/frontend/flutter_vision-master/example/android/app/src/main/AndroidManifest.xml b/frontend/flutter_vision-master/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..51056b1f83 --- /dev/null +++ b/frontend/flutter_vision-master/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + diff --git a/frontend/flutter_vision-master/example/android/app/src/main/java/com/vladih/computer_vision/flutter_vision_example/MainActivity.java b/frontend/flutter_vision-master/example/android/app/src/main/java/com/vladih/computer_vision/flutter_vision_example/MainActivity.java new file mode 100644 index 0000000000..942c5dfba4 --- /dev/null +++ b/frontend/flutter_vision-master/example/android/app/src/main/java/com/vladih/computer_vision/flutter_vision_example/MainActivity.java @@ -0,0 +1,6 @@ +package com.vladih.computer_vision.flutter_vision_example; + +import io.flutter.embedding.android.FlutterActivity; + +public class MainActivity extends FlutterActivity { +} diff --git a/frontend/flutter_vision-master/example/android/app/src/main/res/drawable-v21/launch_background.xml b/frontend/flutter_vision-master/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000000..f74085f3f6 --- /dev/null +++ b/frontend/flutter_vision-master/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/frontend/flutter_vision-master/example/android/app/src/main/res/drawable/launch_background.xml b/frontend/flutter_vision-master/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000000..304732f884 --- /dev/null +++ b/frontend/flutter_vision-master/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/frontend/flutter_vision-master/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/frontend/flutter_vision-master/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000..db77bb4b7b Binary files /dev/null and b/frontend/flutter_vision-master/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/frontend/flutter_vision-master/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/frontend/flutter_vision-master/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000..17987b79bb Binary files /dev/null and b/frontend/flutter_vision-master/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/frontend/flutter_vision-master/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/frontend/flutter_vision-master/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000..09d4391482 Binary files /dev/null and b/frontend/flutter_vision-master/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/frontend/flutter_vision-master/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/frontend/flutter_vision-master/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..d5f1c8d34e Binary files /dev/null and b/frontend/flutter_vision-master/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/frontend/flutter_vision-master/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/frontend/flutter_vision-master/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000..4d6372eebd Binary files /dev/null and b/frontend/flutter_vision-master/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/frontend/flutter_vision-master/example/android/app/src/main/res/values-night/styles.xml b/frontend/flutter_vision-master/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000000..3db14bb539 --- /dev/null +++ b/frontend/flutter_vision-master/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/frontend/flutter_vision-master/example/android/app/src/main/res/values/styles.xml b/frontend/flutter_vision-master/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000000..d460d1e921 --- /dev/null +++ b/frontend/flutter_vision-master/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/frontend/flutter_vision-master/example/android/app/src/profile/AndroidManifest.xml b/frontend/flutter_vision-master/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000000..8117cc51fe --- /dev/null +++ b/frontend/flutter_vision-master/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/frontend/flutter_vision-master/example/android/build.gradle b/frontend/flutter_vision-master/example/android/build.gradle new file mode 100644 index 0000000000..0a2d6a10f9 --- /dev/null +++ b/frontend/flutter_vision-master/example/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.6.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:4.1.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/frontend/flutter_vision-master/example/android/gradle.properties b/frontend/flutter_vision-master/example/android/gradle.properties new file mode 100644 index 0000000000..d5466d8af3 --- /dev/null +++ b/frontend/flutter_vision-master/example/android/gradle.properties @@ -0,0 +1,4 @@ +#org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true +org.gradle.jvmargs=-Xmx4096m diff --git a/frontend/flutter_vision-master/example/android/gradle/wrapper/gradle-wrapper.properties b/frontend/flutter_vision-master/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..eeaff8aa63 --- /dev/null +++ b/frontend/flutter_vision-master/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Feb 22 16:51:52 CET 2023 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/frontend/flutter_vision-master/example/android/settings.gradle b/frontend/flutter_vision-master/example/android/settings.gradle new file mode 100644 index 0000000000..44e62bcf06 --- /dev/null +++ b/frontend/flutter_vision-master/example/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/frontend/flutter_vision-master/example/assets/labels.txt b/frontend/flutter_vision-master/example/assets/labels.txt new file mode 100644 index 0000000000..1f42c8eb44 --- /dev/null +++ b/frontend/flutter_vision-master/example/assets/labels.txt @@ -0,0 +1,80 @@ +person +bicycle +car +motorcycle +airplane +bus +train +truck +boat +traffic light +fire hydrant +stop sign +parking meter +bench +bird +cat +dog +horse +sheep +cow +elephant +bear +zebra +giraffe +backpack +umbrella +handbag +tie +suitcase +frisbee +skis +snowboard +sports ball +kite +baseball bat +baseball glove +skateboard +surfboard +tennis racket +bottle +wine glass +cup +fork +knife +spoon +bowl +banana +apple +sandwich +orange +broccoli +carrot +hot dog +pizza +donut +cake +chair +couch +potted plant +bed +dining table +toilet +tv +laptop +mouse +remote +keyboard +cell phone +microwave +oven +toaster +sink +refrigerator +book +clock +vase +scissors +teddy bear +hair drier +toothbrush \ No newline at end of file diff --git a/frontend/flutter_vision-master/example/assets/tessdata/spa.traineddata b/frontend/flutter_vision-master/example/assets/tessdata/spa.traineddata new file mode 100644 index 0000000000..f703e0535e Binary files /dev/null and b/frontend/flutter_vision-master/example/assets/tessdata/spa.traineddata differ diff --git a/frontend/flutter_vision-master/example/assets/tessdata_config.json b/frontend/flutter_vision-master/example/assets/tessdata_config.json new file mode 100644 index 0000000000..521c2d9ba1 --- /dev/null +++ b/frontend/flutter_vision-master/example/assets/tessdata_config.json @@ -0,0 +1,5 @@ +{ + "files": [ + "spa.traineddata" + ] + } \ No newline at end of file diff --git a/frontend/flutter_vision-master/example/assets/yolov5n.tflite b/frontend/flutter_vision-master/example/assets/yolov5n.tflite new file mode 100644 index 0000000000..0ccf9e4f18 Binary files /dev/null and b/frontend/flutter_vision-master/example/assets/yolov5n.tflite differ diff --git a/frontend/flutter_vision-master/example/assets/yolov8n-seg.tflite b/frontend/flutter_vision-master/example/assets/yolov8n-seg.tflite new file mode 100644 index 0000000000..9f089da3f6 Binary files /dev/null and b/frontend/flutter_vision-master/example/assets/yolov8n-seg.tflite differ diff --git a/frontend/flutter_vision-master/example/assets/yolov8n.tflite b/frontend/flutter_vision-master/example/assets/yolov8n.tflite new file mode 100644 index 0000000000..b8aeb41b16 Binary files /dev/null and b/frontend/flutter_vision-master/example/assets/yolov8n.tflite differ diff --git a/frontend/flutter_vision-master/example/ios/.gitignore b/frontend/flutter_vision-master/example/ios/.gitignore new file mode 100644 index 0000000000..7a7f9873ad --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/frontend/flutter_vision-master/example/ios/Flutter/AppFrameworkInfo.plist b/frontend/flutter_vision-master/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000000..8d4492f977 --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 9.0 + + diff --git a/frontend/flutter_vision-master/example/ios/Flutter/Debug.xcconfig b/frontend/flutter_vision-master/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000000..592ceee85b --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/frontend/flutter_vision-master/example/ios/Flutter/Release.xcconfig b/frontend/flutter_vision-master/example/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000000..592ceee85b --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/frontend/flutter_vision-master/example/ios/Runner.xcodeproj/project.pbxproj b/frontend/flutter_vision-master/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..182c3f120b --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,481 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.vladih.computervision.flutterVisionExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.vladih.computervision.flutterVisionExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.vladih.computervision.flutterVisionExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/frontend/flutter_vision-master/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/frontend/flutter_vision-master/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..919434a625 --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/frontend/flutter_vision-master/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/flutter_vision-master/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/frontend/flutter_vision-master/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/frontend/flutter_vision-master/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000..f9b0d7c5ea --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/frontend/flutter_vision-master/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/frontend/flutter_vision-master/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000000..c87d15a335 --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/flutter_vision-master/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/frontend/flutter_vision-master/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..1d526a16ed --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/frontend/flutter_vision-master/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/flutter_vision-master/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/frontend/flutter_vision-master/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/frontend/flutter_vision-master/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000..f9b0d7c5ea --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/frontend/flutter_vision-master/example/ios/Runner/AppDelegate.swift b/frontend/flutter_vision-master/example/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000000..70693e4a8c --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..d36b1fab2d --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000..dc9ada4725 Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000000..28c6bf0301 Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000000..2ccbfd967d Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000..f091b6b0bc Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000000..4cde12118d Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000..d0ef06e7ed Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000000..dcdc2306c2 Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000000..2ccbfd967d Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000..c8f9ed8f5c Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000..a6d6b8609d Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000..a6d6b8609d Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000..75b2d164a5 Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000..c4df70d39d Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000000..6a84f41e14 Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000000..d0e1f58536 Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000000..0bedcf2fd4 --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000000..9da19eacad Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000..9da19eacad Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000..9da19eacad Binary files /dev/null and b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000000..89c2725b70 --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +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. \ No newline at end of file diff --git a/frontend/flutter_vision-master/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/frontend/flutter_vision-master/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000000..f2e259c7c9 --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/flutter_vision-master/example/ios/Runner/Base.lproj/Main.storyboard b/frontend/flutter_vision-master/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000000..f3c28516fb --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/flutter_vision-master/example/ios/Runner/Info.plist b/frontend/flutter_vision-master/example/ios/Runner/Info.plist new file mode 100644 index 0000000000..2c41f84e38 --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Runner/Info.plist @@ -0,0 +1,52 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Flutter Vision + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + flutter_vision_example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + NSCameraUsageDescription + Access to camera is necesary to run flutter_vision plugin + NSMicrophoneUsageDescription + Access to mycrophone is not necesary but camera plugin require it to run flutter_vision plugin + + diff --git a/frontend/flutter_vision-master/example/ios/Runner/Runner-Bridging-Header.h b/frontend/flutter_vision-master/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000000..308a2a560b --- /dev/null +++ b/frontend/flutter_vision-master/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/frontend/flutter_vision-master/example/lib/main.dart b/frontend/flutter_vision-master/example/lib/main.dart new file mode 100644 index 0000000000..5cd7dc89d5 --- /dev/null +++ b/frontend/flutter_vision-master/example/lib/main.dart @@ -0,0 +1,933 @@ +import 'dart:io'; +import 'dart:typed_data'; +import 'dart:ui'; + +import 'package:camera/camera.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_speed_dial/flutter_speed_dial.dart'; +import 'dart:async'; +import 'package:flutter_vision/flutter_vision.dart'; +import 'package:image_picker/image_picker.dart'; + +enum Options { none, imagev5, imagev8, imagev8seg, frame, tesseract, vision } + +late List cameras; +main() async { + WidgetsFlutterBinding.ensureInitialized(); + DartPluginRegistrant.ensureInitialized(); + runApp( + const MaterialApp( + home: MyApp(), + ), + ); +} + +class MyApp extends StatefulWidget { + const MyApp({Key? key}) : super(key: key); + + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + late FlutterVision vision; + Options option = Options.none; + @override + void initState() { + super.initState(); + vision = FlutterVision(); + } + + @override + void dispose() async { + super.dispose(); + await vision.closeTesseractModel(); + await vision.closeYoloModel(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: task(option), + floatingActionButton: SpeedDial( + //margin bottom + icon: Icons.menu, //icon on Floating action button + activeIcon: Icons.close, //icon when menu is expanded on button + backgroundColor: Colors.black12, //background color of button + foregroundColor: Colors.white, //font color, icon color in button + activeBackgroundColor: + Colors.deepPurpleAccent, //background color when menu is expanded + activeForegroundColor: Colors.white, + visible: true, + closeManually: false, + curve: Curves.bounceIn, + overlayColor: Colors.black, + overlayOpacity: 0.5, + buttonSize: const Size(56.0, 56.0), + children: [ + SpeedDialChild( + //speed dial child + child: const Icon(Icons.video_call), + backgroundColor: Colors.red, + foregroundColor: Colors.white, + label: 'Yolo on Frame', + labelStyle: const TextStyle(fontSize: 18.0), + onTap: () { + setState(() { + option = Options.frame; + }); + }, + ), + SpeedDialChild( + child: const Icon(Icons.camera), + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + label: 'YoloV8seg on Image', + labelStyle: const TextStyle(fontSize: 18.0), + onTap: () { + setState(() { + option = Options.imagev8seg; + }); + }, + ), + SpeedDialChild( + child: const Icon(Icons.camera), + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + label: 'YoloV8 on Image', + labelStyle: const TextStyle(fontSize: 18.0), + onTap: () { + setState(() { + option = Options.imagev8; + }); + }, + ), + SpeedDialChild( + child: const Icon(Icons.camera), + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + label: 'YoloV5 on Image', + labelStyle: const TextStyle(fontSize: 18.0), + onTap: () { + setState(() { + option = Options.imagev5; + }); + }, + ), + SpeedDialChild( + child: const Icon(Icons.text_snippet_outlined), + foregroundColor: Colors.white, + backgroundColor: Colors.green, + label: 'Tesseract', + labelStyle: const TextStyle(fontSize: 18.0), + onTap: () { + setState(() { + option = Options.tesseract; + }); + }, + ), + // SpeedDialChild( + // child: const Icon(Icons.document_scanner), + // foregroundColor: Colors.white, + // backgroundColor: Colors.green, + // label: 'Vision', + // labelStyle: const TextStyle(fontSize: 18.0), + // onTap: () { + // setState(() { + // option = Options.vision; + // }); + // }, + // ), + ], + ), + ); + } + + Widget task(Options option) { + if (option == Options.frame) { + return YoloVideo(vision: vision); + } + if (option == Options.imagev5) { + return YoloImageV5(vision: vision); + } + if (option == Options.imagev8) { + return YoloImageV8(vision: vision); + } + if (option == Options.imagev8seg) { + return YoloImageV8Seg(vision: vision); + } + if (option == Options.tesseract) { + return TesseractImage(vision: vision); + } + return const Center(child: Text("Choose Task")); + } +} + +class YoloVideo extends StatefulWidget { + final FlutterVision vision; + const YoloVideo({Key? key, required this.vision}) : super(key: key); + + @override + State createState() => _YoloVideoState(); +} + +class _YoloVideoState extends State { + late CameraController controller; + late List> yoloResults; + CameraImage? cameraImage; + bool isLoaded = false; + bool isDetecting = false; + + @override + void initState() { + super.initState(); + init(); + } + + init() async { + cameras = await availableCameras(); + controller = CameraController(cameras[0], ResolutionPreset.medium); + controller.initialize().then((value) { + loadYoloModel().then((value) { + setState(() { + isLoaded = true; + isDetecting = false; + yoloResults = []; + }); + }); + }); + } + + @override + void dispose() async { + super.dispose(); + controller.dispose(); + } + + @override + Widget build(BuildContext context) { + final Size size = MediaQuery.of(context).size; + if (!isLoaded) { + return const Scaffold( + body: Center( + child: Text("Model not loaded, waiting for it"), + ), + ); + } + return Stack( + fit: StackFit.expand, + children: [ + AspectRatio( + aspectRatio: controller.value.aspectRatio, + child: CameraPreview( + controller, + ), + ), + ...displayBoxesAroundRecognizedObjects(size), + Positioned( + bottom: 75, + width: MediaQuery.of(context).size.width, + child: Container( + height: 80, + width: 80, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + width: 5, color: Colors.white, style: BorderStyle.solid), + ), + child: isDetecting + ? IconButton( + onPressed: () async { + stopDetection(); + }, + icon: const Icon( + Icons.stop, + color: Colors.red, + ), + iconSize: 50, + ) + : IconButton( + onPressed: () async { + await startDetection(); + }, + icon: const Icon( + Icons.play_arrow, + color: Colors.white, + ), + iconSize: 50, + ), + ), + ), + ], + ); + } + + Future loadYoloModel() async { + await widget.vision.loadYoloModel( + labels: 'assets/labels.txt', + modelPath: 'assets/yolov8n.tflite', + modelVersion: "yolov8", + numThreads: 2, + useGpu: true); + setState(() { + isLoaded = true; + }); + } + + Future yoloOnFrame(CameraImage cameraImage) async { + final result = await widget.vision.yoloOnFrame( + bytesList: cameraImage.planes.map((plane) => plane.bytes).toList(), + imageHeight: cameraImage.height, + imageWidth: cameraImage.width, + iouThreshold: 0.4, + confThreshold: 0.4, + classThreshold: 0.5); + if (result.isNotEmpty) { + setState(() { + yoloResults = result; + }); + } + } + + Future startDetection() async { + setState(() { + isDetecting = true; + }); + if (controller.value.isStreamingImages) { + return; + } + await controller.startImageStream((image) async { + if (isDetecting) { + cameraImage = image; + yoloOnFrame(image); + } + }); + } + + Future stopDetection() async { + setState(() { + isDetecting = false; + yoloResults.clear(); + }); + } + + List displayBoxesAroundRecognizedObjects(Size screen) { + if (yoloResults.isEmpty) return []; + double factorX = screen.width / (cameraImage?.height ?? 1); + double factorY = screen.height / (cameraImage?.width ?? 1); + + Color colorPick = const Color.fromARGB(255, 50, 233, 30); + + return yoloResults.map((result) { + return Positioned( + left: result["box"][0] * factorX, + top: result["box"][1] * factorY, + width: (result["box"][2] - result["box"][0]) * factorX, + height: (result["box"][3] - result["box"][1]) * factorY, + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(10.0)), + border: Border.all(color: Colors.pink, width: 2.0), + ), + child: Text( + "${result['tag']} ${(result['box'][4] * 100).toStringAsFixed(0)}%", + style: TextStyle( + background: Paint()..color = colorPick, + color: Colors.white, + fontSize: 18.0, + ), + ), + ), + ); + }).toList(); + } +} + +class YoloImageV5 extends StatefulWidget { + final FlutterVision vision; + const YoloImageV5({Key? key, required this.vision}) : super(key: key); + + @override + State createState() => _YoloImageV5State(); +} + +class _YoloImageV5State extends State { + late List> yoloResults; + File? imageFile; + int imageHeight = 1; + int imageWidth = 1; + bool isLoaded = false; + + @override + void initState() { + super.initState(); + loadYoloModel().then((value) { + setState(() { + yoloResults = []; + isLoaded = true; + }); + }); + } + + @override + void dispose() async { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final Size size = MediaQuery.of(context).size; + if (!isLoaded) { + return const Scaffold( + body: Center( + child: Text("Model not loaded, waiting for it"), + ), + ); + } + return Stack( + fit: StackFit.expand, + children: [ + imageFile != null ? Image.file(imageFile!) : const SizedBox(), + Align( + alignment: Alignment.bottomCenter, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextButton( + onPressed: pickImage, + child: const Text("Pick image"), + ), + ElevatedButton( + onPressed: yoloOnImage, + child: const Text("Detect"), + ) + ], + ), + ), + ...displayBoxesAroundRecognizedObjects(size), + ], + ); + } + + Future loadYoloModel() async { + await widget.vision.loadYoloModel( + labels: 'assets/labels.txt', + modelPath: 'assets/yolov5n.tflite', + modelVersion: "yolov5", + quantization: false, + numThreads: 2, + useGpu: true); + setState(() { + isLoaded = true; + }); + } + + Future pickImage() async { + final ImagePicker picker = ImagePicker(); + // Capture a photo + final XFile? photo = await picker.pickImage(source: ImageSource.gallery); + if (photo != null) { + setState(() { + imageFile = File(photo.path); + }); + } + } + + yoloOnImage() async { + yoloResults.clear(); + Uint8List byte = await imageFile!.readAsBytes(); + final image = await decodeImageFromList(byte); + imageHeight = image.height; + imageWidth = image.width; + final result = await widget.vision.yoloOnImage( + bytesList: byte, + imageHeight: image.height, + imageWidth: image.width, + iouThreshold: 0.8, + confThreshold: 0.4, + classThreshold: 0.5); + if (result.isNotEmpty) { + setState(() { + yoloResults = result; + }); + } + } + + List displayBoxesAroundRecognizedObjects(Size screen) { + if (yoloResults.isEmpty) return []; + + double factorX = screen.width / (imageWidth); + double imgRatio = imageWidth / imageHeight; + double newWidth = imageWidth * factorX; + double newHeight = newWidth / imgRatio; + double factorY = newHeight / (imageHeight); + + double pady = (screen.height - newHeight) / 2; + + Color colorPick = const Color.fromARGB(255, 50, 233, 30); + return yoloResults.map((result) { + return Positioned( + left: result["box"][0] * factorX, + top: result["box"][1] * factorY + pady, + width: (result["box"][2] - result["box"][0]) * factorX, + height: (result["box"][3] - result["box"][1]) * factorY, + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(10.0)), + border: Border.all(color: Colors.pink, width: 2.0), + ), + child: Text( + "${result['tag']} ${(result['box'][4] * 100).toStringAsFixed(0)}%", + style: TextStyle( + background: Paint()..color = colorPick, + color: Colors.white, + fontSize: 18.0, + ), + ), + ), + ); + }).toList(); + } +} + +class YoloImageV8 extends StatefulWidget { + final FlutterVision vision; + const YoloImageV8({Key? key, required this.vision}) : super(key: key); + + @override + State createState() => _YoloImageV8State(); +} + +class _YoloImageV8State extends State { + late List> yoloResults; + File? imageFile; + int imageHeight = 1; + int imageWidth = 1; + bool isLoaded = false; + + @override + void initState() { + super.initState(); + loadYoloModel().then((value) { + setState(() { + yoloResults = []; + isLoaded = true; + }); + }); + } + + @override + void dispose() async { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final Size size = MediaQuery.of(context).size; + if (!isLoaded) { + return const Scaffold( + body: Center( + child: Text("Model not loaded, waiting for it"), + ), + ); + } + return Stack( + fit: StackFit.expand, + children: [ + imageFile != null ? Image.file(imageFile!) : const SizedBox(), + Align( + alignment: Alignment.bottomCenter, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextButton( + onPressed: pickImage, + child: const Text("Pick an image"), + ), + ElevatedButton( + onPressed: yoloOnImage, + child: const Text("Detect"), + ) + ], + ), + ), + ...displayBoxesAroundRecognizedObjects(size), + ], + ); + } + + Future loadYoloModel() async { + await widget.vision.loadYoloModel( + labels: 'assets/labels.txt', + modelPath: 'assets/yolov8n.tflite', + modelVersion: "yolov8", + quantization: false, + numThreads: 2, + useGpu: true); + setState(() { + isLoaded = true; + }); + } + + Future pickImage() async { + final ImagePicker picker = ImagePicker(); + // Capture a photo + final XFile? photo = await picker.pickImage(source: ImageSource.gallery); + if (photo != null) { + setState(() { + imageFile = File(photo.path); + }); + } + } + + yoloOnImage() async { + yoloResults.clear(); + Uint8List byte = await imageFile!.readAsBytes(); + final image = await decodeImageFromList(byte); + imageHeight = image.height; + imageWidth = image.width; + final result = await widget.vision.yoloOnImage( + bytesList: byte, + imageHeight: image.height, + imageWidth: image.width, + iouThreshold: 0.8, + confThreshold: 0.4, + classThreshold: 0.5); + if (result.isNotEmpty) { + setState(() { + yoloResults = result; + }); + } + } + + List displayBoxesAroundRecognizedObjects(Size screen) { + if (yoloResults.isEmpty) return []; + + double factorX = screen.width / (imageWidth); + double imgRatio = imageWidth / imageHeight; + double newWidth = imageWidth * factorX; + double newHeight = newWidth / imgRatio; + double factorY = newHeight / (imageHeight); + + double pady = (screen.height - newHeight) / 2; + + Color colorPick = const Color.fromARGB(255, 50, 233, 30); + return yoloResults.map((result) { + return Positioned( + left: result["box"][0] * factorX, + top: result["box"][1] * factorY + pady, + width: (result["box"][2] - result["box"][0]) * factorX, + height: (result["box"][3] - result["box"][1]) * factorY, + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(10.0)), + border: Border.all(color: Colors.pink, width: 2.0), + ), + child: Text( + "${result['tag']} ${(result['box'][4] * 100).toStringAsFixed(0)}%", + style: TextStyle( + background: Paint()..color = colorPick, + color: Colors.white, + fontSize: 18.0, + ), + ), + ), + ); + }).toList(); + } +} + +class YoloImageV8Seg extends StatefulWidget { + final FlutterVision vision; + const YoloImageV8Seg({Key? key, required this.vision}) : super(key: key); + + @override + State createState() => _YoloImageV8SegState(); +} + +class _YoloImageV8SegState extends State { + late List> yoloResults; + File? imageFile; + int imageHeight = 1; + int imageWidth = 1; + bool isLoaded = false; + + @override + void initState() { + super.initState(); + loadYoloModel().then((value) { + setState(() { + yoloResults = []; + isLoaded = true; + }); + }); + } + + @override + void dispose() async { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final Size size = MediaQuery.of(context).size; + if (!isLoaded) { + return const Scaffold( + body: Center( + child: Text("Model not loaded, waiting for it"), + ), + ); + } + return Stack( + fit: StackFit.expand, + children: [ + imageFile != null ? Image.file(imageFile!) : const SizedBox(), + Align( + alignment: Alignment.bottomCenter, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextButton( + onPressed: pickImage, + child: const Text("Pick image"), + ), + ElevatedButton( + onPressed: yoloOnImage, + child: const Text("Detect"), + ) + ], + ), + ), + ...displayBoxesAroundRecognizedObjects(size), + ], + ); + } + + Future loadYoloModel() async { + await widget.vision.loadYoloModel( + labels: 'assets/labels.txt', + modelPath: 'assets/yolov8n-seg.tflite', + modelVersion: "yolov8seg", + quantization: false, + numThreads: 2, + useGpu: true); + setState(() { + isLoaded = true; + }); + } + + Future pickImage() async { + final ImagePicker picker = ImagePicker(); + // Capture a photo + final XFile? photo = await picker.pickImage(source: ImageSource.gallery); + if (photo != null) { + setState(() { + imageFile = File(photo.path); + }); + } + } + + yoloOnImage() async { + yoloResults.clear(); + Uint8List byte = await imageFile!.readAsBytes(); + final image = await decodeImageFromList(byte); + imageHeight = image.height; + imageWidth = image.width; + final result = await widget.vision.yoloOnImage( + bytesList: byte, + imageHeight: image.height, + imageWidth: image.width, + iouThreshold: 0.8, + confThreshold: 0.4, + classThreshold: 0.5); + if (result.isNotEmpty) { + setState(() { + yoloResults = result; + }); + } + } + + List displayBoxesAroundRecognizedObjects(Size screen) { + if (yoloResults.isEmpty) return []; + + double factorX = screen.width / (imageWidth); + double imgRatio = imageWidth / imageHeight; + double newWidth = imageWidth * factorX; + double newHeight = newWidth / imgRatio; + double factorY = newHeight / (imageHeight); + + double pady = (screen.height - newHeight) / 2; + + Color colorPick = const Color.fromARGB(255, 50, 233, 30); + return yoloResults.map((result) { + return Stack(children: [ + Positioned( + left: result["box"][0] * factorX, + top: result["box"][1] * factorY + pady, + width: (result["box"][2] - result["box"][0]) * factorX, + height: (result["box"][3] - result["box"][1]) * factorY, + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(10.0)), + border: Border.all(color: Colors.pink, width: 2.0), + ), + child: Text( + "${result['tag']} ${(result['box'][4] * 100).toStringAsFixed(0)}%", + style: TextStyle( + background: Paint()..color = colorPick, + color: Colors.white, + fontSize: 18.0, + ), + ), + ), + ), + Positioned( + left: result["box"][0] * factorX, + top: result["box"][1] * factorY + pady, + width: (result["box"][2] - result["box"][0]) * factorX, + height: (result["box"][3] - result["box"][1]) * factorY, + child: CustomPaint( + painter: PolygonPainter( + points: (result["polygons"] as List).map((e) { + Map xy = Map.from(e); + xy['x'] = (xy['x'] as double) * factorX; + xy['y'] = (xy['y'] as double) * factorY; + return xy; + }).toList()), + )), + ]); + }).toList(); + } +} + +class PolygonPainter extends CustomPainter { + final List> points; + + PolygonPainter({required this.points}); + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..color = const Color.fromARGB(129, 255, 2, 124) + ..strokeWidth = 2 + ..style = PaintingStyle.fill; + + final path = Path(); + if (points.isNotEmpty) { + path.moveTo(points[0]['x']!, points[0]['y']!); + for (var i = 1; i < points.length; i++) { + path.lineTo(points[i]['x']!, points[i]['y']!); + } + path.close(); + } + + canvas.drawPath(path, paint); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return false; + } +} + +class TesseractImage extends StatefulWidget { + final FlutterVision vision; + const TesseractImage({Key? key, required this.vision}) : super(key: key); + + @override + State createState() => _TesseractImageState(); +} + +class _TesseractImageState extends State { + late List> tesseractResults = []; + File? imageFile; + bool isLoaded = false; + + @override + void initState() { + super.initState(); + loadTesseractModel().then((value) { + setState(() { + isLoaded = true; + tesseractResults = []; + }); + }); + } + + @override + void dispose() async { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + if (!isLoaded) { + return const Scaffold( + body: Center( + child: Text("Model not loaded, waiting for it"), + ), + ); + } + return Center( + child: SingleChildScrollView( + child: Column( + children: [ + imageFile != null ? Image.file(imageFile!) : const SizedBox(), + tesseractResults.isEmpty + ? const SizedBox() + : Align(child: Text(tesseractResults[0]["text"])), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextButton( + onPressed: pickImage, + child: const Text("Pick an image"), + ), + ElevatedButton( + onPressed: tesseractOnImage, + child: const Text("Get Text"), + ) + ], + ), + ], + ), + ), + ); + } + + Future loadTesseractModel() async { + await widget.vision.loadTesseractModel( + args: { + 'psm': '11', + 'oem': '1', + 'preserve_interword_spaces': '1', + }, + language: 'spa', + ); + setState(() { + isLoaded = true; + }); + } + + Future pickImage() async { + final ImagePicker picker = ImagePicker(); + // Capture a photo + final XFile? photo = await picker.pickImage(source: ImageSource.gallery); + if (photo != null) { + setState(() { + imageFile = File(photo.path); + }); + } + } + + tesseractOnImage() async { + tesseractResults.clear(); + Uint8List byte = await imageFile!.readAsBytes(); + final result = await widget.vision.tesseractOnImage(bytesList: byte); + if (result.isNotEmpty) { + setState(() { + tesseractResults = result; + }); + } + } +} diff --git a/frontend/flutter_vision-master/example/pubspec.lock b/frontend/flutter_vision-master/example/pubspec.lock new file mode 100644 index 0000000000..ea616238d1 --- /dev/null +++ b/frontend/flutter_vision-master/example/pubspec.lock @@ -0,0 +1,457 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + camera: + dependency: "direct main" + description: + name: camera + sha256: "3ad71371b8168a4c8012c0b40a53c05afc75d46cc688b0f37b4611a841d47b25" + url: "https://pub.dev" + source: hosted + version: "0.9.8+1" + camera_android: + dependency: transitive + description: + name: camera_android + sha256: "665d62c1f334722c7519ca5d3b94ad68ecaa801691870602da5638a42c1fff67" + url: "https://pub.dev" + source: hosted + version: "0.9.8+3" + camera_avfoundation: + dependency: transitive + description: + name: camera_avfoundation + sha256: "6a68c20593d4cd58974d555f74a48b244f9db28cc9156de57781122d11b8754b" + url: "https://pub.dev" + source: hosted + version: "0.9.11" + camera_platform_interface: + dependency: transitive + description: + name: camera_platform_interface + sha256: b632be28e61d00a233f67d98ea90fd7041956f27a1c65500188ee459be60e15f + url: "https://pub.dev" + source: hosted + version: "2.4.0" + camera_web: + dependency: transitive + description: + name: camera_web + sha256: "18cdbee5441e9a6fb129fdd9b68a06d1b8c5236932ba97d5faeaefe80db2e5bd" + url: "https://pub.dev" + source: hosted + version: "0.2.1+6" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + url: "https://pub.dev" + source: hosted + version: "1.17.2" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" + url: "https://pub.dev" + source: hosted + version: "0.3.3+4" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" + source: hosted + version: "1.0.5" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" + source: hosted + version: "2.0.1" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "60fc7b78455b94e6de2333d2f95196d32cf5c22f4b0b0520a628804cb463503b" + url: "https://pub.dev" + source: hosted + version: "2.0.7" + flutter_speed_dial: + dependency: "direct main" + description: + name: flutter_speed_dial + sha256: "41d7ad0bc224248637b3a5e0b9083e912a75445bdb450cf82b8ed06d7af7c61d" + url: "https://pub.dev" + source: hosted + version: "6.2.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_vision: + dependency: "direct main" + description: + path: ".." + relative: true + source: path + version: "1.1.2" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + http: + dependency: transitive + description: + name: http + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + url: "https://pub.dev" + source: hosted + version: "0.13.5" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "22207768556b82d55ec70166824350fee32298732d5efa4d6e756f848f51f66a" + url: "https://pub.dev" + source: hosted + version: "0.8.6+3" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "68d067baf7f6e401b1124ee83dd6967e67847314250fd68012aab34a69beb344" + url: "https://pub.dev" + source: hosted + version: "0.8.5+7" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "66fc6e3877bbde82c33d122f3588777c3784ac5bd7d1cdd79213ef7aecb85b34" + url: "https://pub.dev" + source: hosted + version: "2.1.11" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: "39aa70b5f1e5e7c94585b9738632d5fdb764a5655e40cd9e7b95fbd2fc50c519" + url: "https://pub.dev" + source: hosted + version: "0.8.6+9" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "1991219d9dbc42a99aff77e663af8ca51ced592cd6685c9485e3458302d3d4f8" + url: "https://pub.dev" + source: hosted + version: "2.6.3" + js: + dependency: transitive + description: + name: js + sha256: a5e201311cb08bf3912ebbe9a2be096e182d703f881136ec1e81a2338a9e120d + url: "https://pub.dev" + source: hosted + version: "0.6.4" + lints: + dependency: transitive + description: + name: lints + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + url: "https://pub.dev" + source: hosted + version: "0.12.16" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + meta: + dependency: transitive + description: + name: meta + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + path: + dependency: transitive + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" + source: hosted + version: "1.8.3" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95 + url: "https://pub.dev" + source: hosted + version: "2.0.12" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e + url: "https://pub.dev" + source: hosted + version: "2.0.22" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: "2e32f1640f07caef0d3cb993680f181c79e54a3827b997d5ee221490d131fbd9" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76 + url: "https://pub.dev" + source: hosted + version: "2.0.5" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bcabbe399d4042b8ee687e17548d5d3f527255253b4a639f5f8d2094a9c2b45c + url: "https://pub.dev" + source: hosted + version: "2.1.3" + platform: + dependency: transitive + description: + name: platform + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + url: "https://pub.dev" + source: hosted + version: "2.1.3" + process: + dependency: transitive + description: + name: process + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" + source: hosted + version: "4.2.4" + quiver: + dependency: transitive + description: + name: quiver + sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 + url: "https://pub.dev" + source: hosted + version: "3.2.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + url: "https://pub.dev" + source: hosted + version: "0.6.0" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" + win32: + dependency: transitive + description: + name: win32 + sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 + url: "https://pub.dev" + source: hosted + version: "3.1.3" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 + url: "https://pub.dev" + source: hosted + version: "1.0.0" +sdks: + dart: ">=3.1.0-185.0.dev <4.0.0" + flutter: ">=3.0.0" diff --git a/frontend/flutter_vision-master/example/pubspec.yaml b/frontend/flutter_vision-master/example/pubspec.yaml new file mode 100644 index 0000000000..c29ed4a64a --- /dev/null +++ b/frontend/flutter_vision-master/example/pubspec.yaml @@ -0,0 +1,74 @@ +name: flutter_vision_example +description: Demonstrates how to use the flutter_vision plugin. + +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: "none" # Remove this line if you wish to publish to pub.dev + +environment: + sdk: ">=2.17.1 <3.0.0" + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + camera: ^0.9.8+1 + cupertino_icons: ^1.0.5 + flutter: + sdk: flutter + flutter_vision: + path: ../ + flutter_speed_dial: ^6.2.0 + image_picker: ^0.8.6+3 + +dev_dependencies: + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.1 + flutter_test: + sdk: flutter + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec +# The following section is specific to Flutter. +flutter: + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + assets: + - assets/ + - assets/labels.txt + - assets/yolov5n.tflite + - assets/tessdata/ + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/frontend/flutter_vision-master/example/test/widget_test.dart b/frontend/flutter_vision-master/example/test/widget_test.dart new file mode 100644 index 0000000000..55da4f5403 --- /dev/null +++ b/frontend/flutter_vision-master/example/test/widget_test.dart @@ -0,0 +1,27 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +// import 'package:flutter_vision_example/main.dart'; + +void main() { + testWidgets('Verify Platform version', (WidgetTester tester) async { + // Build our app and trigger a frame. + //await tester.pumpWidget(const MyApp()); + + // Verify that platform version is retrieved. + expect( + find.byWidgetPredicate( + (Widget widget) => + widget is Text && widget.data!.startsWith('Running on:'), + ), + findsOneWidget, + ); + }); +} diff --git a/frontend/flutter_vision-master/ios/.gitignore b/frontend/flutter_vision-master/ios/.gitignore new file mode 100644 index 0000000000..0c885071e3 --- /dev/null +++ b/frontend/flutter_vision-master/ios/.gitignore @@ -0,0 +1,38 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ +GeneratedPluginRegistrant.h +GeneratedPluginRegistrant.m + +.generated/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + +/Flutter/Generated.xcconfig +/Flutter/ephemeral/ +/Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/frontend/flutter_vision-master/ios/Assets/.gitkeep b/frontend/flutter_vision-master/ios/Assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/flutter_vision-master/ios/Classes/FlutterVisionPlugin.h b/frontend/flutter_vision-master/ios/Classes/FlutterVisionPlugin.h new file mode 100644 index 0000000000..00292d490f --- /dev/null +++ b/frontend/flutter_vision-master/ios/Classes/FlutterVisionPlugin.h @@ -0,0 +1,4 @@ +#import + +@interface FlutterVisionPlugin : NSObject +@end diff --git a/frontend/flutter_vision-master/ios/Classes/FlutterVisionPlugin.m b/frontend/flutter_vision-master/ios/Classes/FlutterVisionPlugin.m new file mode 100644 index 0000000000..e9df5fd95e --- /dev/null +++ b/frontend/flutter_vision-master/ios/Classes/FlutterVisionPlugin.m @@ -0,0 +1,15 @@ +#import "FlutterVisionPlugin.h" +#if __has_include() +#import +#else +// Support project import fallback if the generated compatibility header +// is not copied when this plugin is created as a library. +// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 +#import "flutter_vision-Swift.h" +#endif + +@implementation FlutterVisionPlugin ++ (void)registerWithRegistrar:(NSObject*)registrar { + [SwiftFlutterVisionPlugin registerWithRegistrar:registrar]; +} +@end diff --git a/frontend/flutter_vision-master/ios/Classes/SwiftFlutterVisionPlugin.swift b/frontend/flutter_vision-master/ios/Classes/SwiftFlutterVisionPlugin.swift new file mode 100644 index 0000000000..3bbaa51904 --- /dev/null +++ b/frontend/flutter_vision-master/ios/Classes/SwiftFlutterVisionPlugin.swift @@ -0,0 +1,14 @@ +import Flutter +import UIKit + +public class SwiftFlutterVisionPlugin: NSObject, FlutterPlugin { + public static func register(with registrar: FlutterPluginRegistrar) { + let channel = FlutterMethodChannel(name: "flutter_vision", binaryMessenger: registrar.messenger()) + let instance = SwiftFlutterVisionPlugin() + registrar.addMethodCallDelegate(instance, channel: channel) + } + + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + result("iOS " + UIDevice.current.systemVersion) + } +} diff --git a/frontend/flutter_vision-master/ios/flutter_vision.podspec b/frontend/flutter_vision-master/ios/flutter_vision.podspec new file mode 100644 index 0000000000..03e44c49d6 --- /dev/null +++ b/frontend/flutter_vision-master/ios/flutter_vision.podspec @@ -0,0 +1,23 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint flutter_vision.podspec` to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'flutter_vision' + s.version = '0.0.1' + s.summary = 'A new flutter plugin project.' + s.description = <<-DESC +A new flutter plugin project. + DESC + s.homepage = 'http://example.com' + s.license = { :file => '../LICENSE' } + s.author = { 'Your Company' => 'email@example.com' } + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.dependency 'Flutter' + s.platform = :ios, '9.0' + + # Flutter.framework does not contain a i386 slice. + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } + s.swift_version = '5.0' +end diff --git a/frontend/flutter_vision-master/lib/flutter_vision.dart b/frontend/flutter_vision-master/lib/flutter_vision.dart new file mode 100644 index 0000000000..993d8cabb2 --- /dev/null +++ b/frontend/flutter_vision-master/lib/flutter_vision.dart @@ -0,0 +1,176 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter_vision/src/plugin/android.dart'; + +abstract class FlutterVision { + factory FlutterVision() { + switch (Platform.operatingSystem) { + case 'android': + return AndroidFlutterVision(); + case 'ios': + throw UnimplementedError('iOS is not supported for now'); + //return IosDniScanner(); + default: + throw UnsupportedError('Unsupported platform'); + } + } + + // ///loadOcrModel: loads both YOLOv5 and Tesseract4 model from the assets folder and + // ///return a ResponseHandler object. + // /// + // ///if the load is successful, it returns a ResponseHandler as a success object, + // ///otherwise it returns a ResponseHandler as an error object + // ///```json:{ + // /// "type": "success" or "error", + // /// "message": "ok", + // /// "data": {}``` + // /// + // /// args: [modelPath] - path to the model file + // /// ,[labelsPath] - path to the labels file + // /// ,[numThreads] - number of threads to use for inference + // /// ,[useGPU] - use GPU for inference + // /// ,[language] - language for tesseract4(en,spa,de,fr,it,nl,ru,pt,tr,zh) + // /// ,[tesseract4Config] - tesseract4 config + // Future loadOcrModel( + // {required String modelPath, + // required String labels, + // int? numThreads, + // bool? useGpu, + // String? language, + // Map? args}); + + // ///scanOnFrame accept a byte List as input and + // ///return a ResponseHandler object. + // /// + // ///if scanOnFrame run without error, it returns a ResponseHandler as a success object, + // ///otherwise it returns a ResponseHandler as an error object. + // /// + // ///```json:{ + // /// "type": 'success', + // /// "message": "ok", + // /// "data": List> + // /// }``` + // ///where map is mapped as follows: + // /// + // ///```Map:{ + // /// "confidence": double, + // /// "box": {x1:double, y1:double, x2:double, y2:double}, + // /// "text": String, + // /// "image": Uint8List, + // /// "tag": String + // /// }``` + // /// + // ///args: [bytesList] - image as byte list + // ///, [imageHeight] - image height + // ///, [imageWidth] - image width + // ///, [classIsText] - list of classes to be detected as text + // ///, [iouThreshold] - intersection over union threshold + // ///, [confThreshold] - confidence threshold + // Future>> ocrOnFrame({ + // required List bytesList, + // required int imageHeight, + // required int imageWidth, + // required List classIsText, + // double? iouThreshold, + // double? confThreshold, + // }); + + // /// dispose OCRModel, clean and save resources + // Future closeOcrModel(); + + ///loadYoloModel: load YOLOv5 model from the assets folder + /// + /// args: [modelPath] - path to the model file + /// ,[labelsPath] - path to the labels file + /// ,[modelVersion] - yolov5, yolov8 + /// ,[quantization] - When set to true, quantized models are used, which can result in faster execution, reduced memory usage, and slightly lower accuracy. + /// ,[numThreads] - number of threads to use for inference + /// ,[useGPU] - use GPU for inference + Future loadYoloModel( + {required String modelPath, + required String labels, + required String modelVersion, + bool? quantization, + int? numThreads, + bool? useGpu}); + + ///yoloOnFrame accept a byte List as input and + ///return a List>. + /// + ///where map is mapped as follow: + /// + ///```Map:{ + /// "box": [x1:left, y1:top, x2:right, y2:bottom, class_confidence] + /// "tag": String: detected class + /// }``` + /// + ///args: [bytesList] - image as byte list + ///, [imageHeight] - image height + ///, [imageWidth] - image width + ///, [iouThreshold] - intersection over union threshold, default 0.4 + ///, [confThreshold] - model confidence threshold, default 0.5, only for [yolov5] + ///, [classThreshold] - class confidence threshold, default 0.5 + Future>> yoloOnFrame({ + required List bytesList, + required int imageHeight, + required int imageWidth, + double? iouThreshold, + double? confThreshold, + double? classThreshold, + }); + + ///yoloOnImage accept a Uint8List as input and + ///return a List>. + /// + ///where map is mapped as follows: + /// + ///```Map:{ + /// "box": [x1:left, y1:top, x2:right, y2:bottom, class_confidence] + /// "tag": String: detected class + /// }``` + /// + ///args: [bytesList] - image bytes + ///, [imageHeight] - image height + ///, [imageWidth] - image width + ///, [iouThreshold] - intersection over union threshold, default 0.4 + ///, [confThreshold] - model confidence threshold, default 0.5, only for [yolov5] + ///, [classThreshold] - class confidence threshold, default 0.5 + Future>> yoloOnImage({ + required Uint8List bytesList, + required int imageHeight, + required int imageWidth, + double? iouThreshold, + double? confThreshold, + double? classThreshold, + }); + + /// dispose OCRModel, clean and save resources + Future closeYoloModel(); + + ///loadTesseractModel: load Tesseract5 model from the assets folder. + /// + /// ,[language] - language for tesseract4(en,spa,de,fr,it,nl,ru,pt,tr,zh) + /// ,[tesseract4Config] - tesseract4 config + Future loadTesseractModel( + {String? language, Map? args}); + + ///tesseractOnImage accept a byte as input and + ///return a List. + /// + ///where map is mapped as follows: + /// + ///```Map:{ + /// "text": String + /// "word_conf": List:int + /// "mean_conf": int + /// }``` + /// + ///args: [bytesList] - image as byte + Future>> tesseractOnImage( + {required Uint8List bytesList}); + + /// dispose Tesseract model, clean and save resources + Future closeTesseractModel(); +} diff --git a/frontend/flutter_vision-master/lib/src/plugin/android.dart b/frontend/flutter_vision-master/lib/src/plugin/android.dart new file mode 100644 index 0000000000..c13f298c1c --- /dev/null +++ b/frontend/flutter_vision-master/lib/src/plugin/android.dart @@ -0,0 +1,245 @@ +import 'dart:typed_data'; + +import '../../flutter_vision.dart'; +import 'base.dart'; + +class AndroidFlutterVision extends BaseFlutterVision implements FlutterVision { + // @override + // Future loadOcrModel( + // {required String modelPath, + // required String labels, + // int? numThreads, + // bool? useGpu, + // String? language, + // Map? args}) async { + // try { + // final String testData = await loadTessData(); + // await channel.invokeMethod('loadOcrModel', { + // 'model_path': modelPath, + // 'is_asset': true, + // 'num_threads': numThreads ?? 1, + // 'use_gpu': useGpu ?? false, + // 'label_path': labels, + // 'image_mean': 0.0, + // 'image_std': 255.0, + // 'rotation': 90, + // 'tess_data': testData, + // 'arg': args, + // 'language': language ?? 'eng' + // }); + // } catch (e) { + // rethrow; + // } + // } + + // @override + // Future>> ocrOnFrame({ + // required List bytesList, + // required int imageHeight, + // required int imageWidth, + // required List classIsText, + // double? iouThreshold, + // double? confThreshold, + // }) async { + // try { + // return await _ocrOnFrame( + // bytesList: bytesList, + // imageHeight: imageHeight, + // imageWidth: imageWidth, + // iouThreshold: iouThreshold ?? 0.4, + // confThreshold: confThreshold ?? 0.5, + // classIsText: classIsText); + // } catch (e) { + // rethrow; + // } + // } + + // Future>> _ocrOnFrame({ + // required List bytesList, + // required int imageHeight, + // required int imageWidth, + // required double iouThreshold, + // required double confThreshold, + // required List classIsText, + // }) async { + // try { + // final x = await channel.invokeMethod>>( + // 'ocrOnFrame', + // { + // "bytesList": bytesList, + // "image_height": imageHeight, + // "image_width": imageWidth, + // "iou_threshold": iouThreshold, + // "conf_threshold": confThreshold, + // "class_is_text": classIsText + // }, + // ); + // return x ?? []; + // } catch (e) { + // rethrow; + // } + // } + + @override + Future loadYoloModel( + {required String modelPath, + required String labels, + required String modelVersion, + bool? quantization, + int? numThreads, + bool? useGpu}) async { + try { + await channel.invokeMethod('loadYoloModel', { + 'model_path': modelPath, + 'is_asset': true, + 'quantization': quantization ?? false, + 'num_threads': numThreads ?? 1, + 'use_gpu': useGpu ?? false, + 'label_path': labels, + 'rotation': 90, + 'model_version': modelVersion + }); + } catch (e) { + rethrow; + } + } + + @override + Future>> yoloOnFrame({ + required List bytesList, + required int imageHeight, + required int imageWidth, + double? iouThreshold, + double? confThreshold, + double? classThreshold, + }) async { + try { + return (await _yoloOnFrame( + bytesList: bytesList, + imageHeight: imageHeight, + imageWidth: imageWidth, + iouThreshold: iouThreshold ?? 0.4, + confThreshold: confThreshold ?? 0.5, + classThreshold: classThreshold ?? 0.5)); + } catch (e) { + rethrow; + } + } + + Future>> _yoloOnFrame({ + required List bytesList, + required int imageHeight, + required int imageWidth, + required double iouThreshold, + required double confThreshold, + required double classThreshold, + }) async { + try { + final x = await channel.invokeMethod>( + 'yoloOnFrame', + { + "bytesList": bytesList, + "image_height": imageHeight, + "image_width": imageWidth, + "iou_threshold": iouThreshold, + "conf_threshold": confThreshold, + "class_threshold": classThreshold + }, + ); + return x?.isNotEmpty ?? false + ? x!.map((e) => Map.from(e)).toList() + : []; + } catch (e) { + // print(e); + rethrow; + } + } + + @override + Future>> yoloOnImage({ + required Uint8List bytesList, + required int imageHeight, + required int imageWidth, + double? iouThreshold, + double? confThreshold, + double? classThreshold, + }) async { + try { + return await _yoloOnImage( + bytesList: bytesList, + imageHeight: imageHeight, + imageWidth: imageWidth, + iouThreshold: iouThreshold ?? 0.4, + confThreshold: confThreshold ?? 0.5, + classThreshold: classThreshold ?? 0.5); + } catch (e) { + rethrow; + } + } + + Future>> _yoloOnImage({ + required Uint8List bytesList, + required int imageHeight, + required int imageWidth, + required double iouThreshold, + required double confThreshold, + required double classThreshold, + }) async { + try { + final x = await channel.invokeMethod>( + 'yoloOnImage', + { + "bytesList": bytesList, + "image_height": imageHeight, + "image_width": imageWidth, + "iou_threshold": iouThreshold, + "conf_threshold": confThreshold, + "class_threshold": classThreshold + }, + ); + return x?.isNotEmpty ?? false + ? x!.map((e) => Map.from(e)).toList() + : []; + } catch (e) { + rethrow; + } + } + + @override + Future loadTesseractModel( + {String? language, Map? args}) async { + try { + final String testData = await loadTessData(); + await channel.invokeMethod('loadTesseractModel', + {'tess_data': testData, 'arg': args, 'language': language ?? 'eng'}); + } catch (e) { + rethrow; + } + } + + @override + Future>> tesseractOnImage({ + required Uint8List bytesList, + }) async { + try { + return await _tesseractOnImage(bytesList: bytesList); + } catch (e) { + rethrow; + } + } + + Future>> _tesseractOnImage( + {required Uint8List bytesList}) async { + try { + final x = await channel.invokeMethod( + 'tesseractOnImage', + { + "bytesList": bytesList, + }, + ); + return x == null ? [] : [Map.from(x)]; + } catch (e) { + rethrow; + } + } +} diff --git a/frontend/flutter_vision-master/lib/src/plugin/base.dart b/frontend/flutter_vision-master/lib/src/plugin/base.dart new file mode 100644 index 0000000000..0245f4def3 --- /dev/null +++ b/frontend/flutter_vision-master/lib/src/plugin/base.dart @@ -0,0 +1,106 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:path/path.dart'; +import 'package:flutter/services.dart'; +import 'package:path_provider/path_provider.dart'; + +abstract class BaseFlutterVision { + // ignore: constant_identifier_names + static const String TESS_DATA_CONFIG = 'assets/tessdata_config.json'; + // ignore: constant_identifier_names + static const String TESS_DATA_PATH = 'assets/tessdata'; + static const MethodChannel _channel = MethodChannel('flutter_vision'); + MethodChannel get channel => _channel; + + Future loadTessData() async { + try { + final Directory appDirectory = await getApplicationDocumentsDirectory(); + final String tessdataDirectory = join(appDirectory.path, 'tessdata'); + + if (!await Directory(tessdataDirectory).exists()) { + await Directory(tessdataDirectory).create(); + } + await copyTessDataToAppDocumentsDirectory(tessdataDirectory); + return appDirectory.path; + } catch (e) { + rethrow; + } + } + + Future copyTessDataToAppDocumentsDirectory(String tessdataDirectory) async { + final String config = await rootBundle.loadString(TESS_DATA_CONFIG); + Map files = jsonDecode(config); + for (var file in files["files"]) { + if (!await File('$tessdataDirectory/$file').exists()) { + final ByteData data = await rootBundle.load('$TESS_DATA_PATH/$file'); + final Uint8List bytes = data.buffer.asUint8List( + data.offsetInBytes, + data.lengthInBytes, + ); + await File('$tessdataDirectory/$file').writeAsBytes(bytes); + } + } + } + + // Future loadOcrModel( + // {required String modelPath, + // required String labels, + // int? numThreads, + // bool? useGpu, + // String? language, + // Map? args}); + + // Future>> ocrOnFrame({ + // required List bytesList, + // required int imageHeight, + // required int imageWidth, + // required List classIsText, + // double? iouThreshold, + // double? confThreshold, + // }); + + // Future closeOcrModel() async { + // await channel.invokeMethod('closeOcrModel'); + // } + + Future loadYoloModel({ + required String modelPath, + required String labels, + required String modelVersion, + bool? quantization, + int? numThreads, + bool? useGpu, + }); + + Future>> yoloOnFrame({ + required List bytesList, + required int imageHeight, + required int imageWidth, + double? iouThreshold, + double? confThreshold, + double? classThreshold, + }); + + Future>> yoloOnImage({ + required Uint8List bytesList, + required int imageHeight, + required int imageWidth, + double? iouThreshold, + double? confThreshold, + double? classThreshold, + }); + + Future closeYoloModel() async { + await channel.invokeMethod('closeYoloModel'); + } + + Future loadTesseractModel( + {String? language, Map? args}); + + Future>> tesseractOnImage( + {required Uint8List bytesList}); + + Future closeTesseractModel() async { + await channel.invokeMethod('closeTesseractModel'); + } +} diff --git a/frontend/flutter_vision-master/pubspec.yaml b/frontend/flutter_vision-master/pubspec.yaml new file mode 100644 index 0000000000..e1cbb827d9 --- /dev/null +++ b/frontend/flutter_vision-master/pubspec.yaml @@ -0,0 +1,65 @@ +name: flutter_vision +description: Plugin for managing Yolov5, Yolov8 and Tesseract v5 accessing with TensorFlow Lite 2.x. Support object detection, segmentation and OCR on Android. iOS, Working in progress. + +version: 1.1.4 + +homepage: https://github.com/vladiH/flutter_vision + +environment: + sdk: ">=2.17.1 <4.0.0" + flutter: ">=2.5.0" + +dependencies: + flutter: + sdk: flutter + path: ^1.8.1 + path_provider: ^2.0.11 + +dev_dependencies: + flutter_lints: ^2.0.1 + flutter_test: + sdk: flutter +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec +# The following section is specific to Flutter. +flutter: + # This section identifies this Flutter project as a plugin project. + # The 'pluginClass' and Android 'package' identifiers should not ordinarily + # be modified. They are used by the tooling to maintain consistency when + # adding or updating assets for this project. + plugin: + platforms: + android: + package: com.vladih.computer_vision.flutter_vision + pluginClass: FlutterVisionPlugin + ios: + pluginClass: FlutterVisionPlugin + # To add assets to your plugin package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + # To add custom fonts to your plugin package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/frontend/flutter_vision-master/test/flutter_vision_test.dart b/frontend/flutter_vision-master/test/flutter_vision_test.dart new file mode 100644 index 0000000000..872da5264a --- /dev/null +++ b/frontend/flutter_vision-master/test/flutter_vision_test.dart @@ -0,0 +1,26 @@ +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +// import 'package:flutter_vision/flutter_vision.dart'; + +void main() { + const MethodChannel channel = MethodChannel('flutter_vision'); + + TestWidgetsFlutterBinding.ensureInitialized(); + + handler(MethodCall methodCall) async { + if (methodCall.method == 'getAll') { + return { + 'appName': 'myapp', + 'packageName': 'com.mycompany.myapp', + 'version': '0.0.1', + 'buildNumber': '1' + }; + } + return null; + } + + TestWidgetsFlutterBinding.ensureInitialized(); + + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(channel, handler); +} diff --git a/frontend/frontend/pradtice/.gitignore b/frontend/frontend/pradtice/.gitignore new file mode 100644 index 0000000000..29a3a5017f --- /dev/null +++ b/frontend/frontend/pradtice/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/frontend/frontend/pradtice/.metadata b/frontend/frontend/pradtice/.metadata new file mode 100644 index 0000000000..8629a4e186 --- /dev/null +++ b/frontend/frontend/pradtice/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "abb292a07e20d696c4568099f918f6c5f330e6b0" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + - platform: android + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + - platform: ios + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + - platform: linux + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + - platform: macos + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + - platform: web + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + - platform: windows + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/frontend/frontend/pradtice/README.md b/frontend/frontend/pradtice/README.md new file mode 100644 index 0000000000..92331de053 --- /dev/null +++ b/frontend/frontend/pradtice/README.md @@ -0,0 +1,16 @@ +# pradtice + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/frontend/frontend/pradtice/analysis_options.yaml b/frontend/frontend/pradtice/analysis_options.yaml new file mode 100644 index 0000000000..0d2902135c --- /dev/null +++ b/frontend/frontend/pradtice/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/frontend/frontend/pradtice/android/.gitignore b/frontend/frontend/pradtice/android/.gitignore new file mode 100644 index 0000000000..6f568019d3 --- /dev/null +++ b/frontend/frontend/pradtice/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/frontend/frontend/pradtice/android/app/build.gradle b/frontend/frontend/pradtice/android/app/build.gradle new file mode 100644 index 0000000000..405a85d680 --- /dev/null +++ b/frontend/frontend/pradtice/android/app/build.gradle @@ -0,0 +1,75 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +android { + namespace "com.example.pradtice" + compileSdk flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.pradtice" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. + minSdkVersion 24 + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } + + dataBinding { + enabled = true + } + aaptOptions { + noCompress 'tflite' + noCompress 'lite' + } +} + +flutter { + source '../..' +} + +dependencies {} diff --git a/frontend/frontend/pradtice/android/app/libs/tmap-sdk-1.2.aar b/frontend/frontend/pradtice/android/app/libs/tmap-sdk-1.2.aar new file mode 100644 index 0000000000..15fc2ffc11 Binary files /dev/null and b/frontend/frontend/pradtice/android/app/libs/tmap-sdk-1.2.aar differ diff --git a/frontend/frontend/pradtice/android/app/libs/vsm-tmap-sdk-v2-android-1.6.60.aar b/frontend/frontend/pradtice/android/app/libs/vsm-tmap-sdk-v2-android-1.6.60.aar new file mode 100644 index 0000000000..3f608eb4f6 Binary files /dev/null and b/frontend/frontend/pradtice/android/app/libs/vsm-tmap-sdk-v2-android-1.6.60.aar differ diff --git a/frontend/frontend/pradtice/android/app/src/debug/AndroidManifest.xml b/frontend/frontend/pradtice/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000000..399f6981d5 --- /dev/null +++ b/frontend/frontend/pradtice/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/frontend/frontend/pradtice/android/app/src/main/AndroidManifest.xml b/frontend/frontend/pradtice/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..fefef967e9 --- /dev/null +++ b/frontend/frontend/pradtice/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/frontend/pradtice/android/app/src/main/kotlin/com/example/pradtice/MainActivity.kt b/frontend/frontend/pradtice/android/app/src/main/kotlin/com/example/pradtice/MainActivity.kt new file mode 100644 index 0000000000..2c30c51a9b --- /dev/null +++ b/frontend/frontend/pradtice/android/app/src/main/kotlin/com/example/pradtice/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.pradtice + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() diff --git a/frontend/frontend/pradtice/android/app/src/main/res/drawable-v21/launch_background.xml b/frontend/frontend/pradtice/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000000..f74085f3f6 --- /dev/null +++ b/frontend/frontend/pradtice/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/frontend/frontend/pradtice/android/app/src/main/res/drawable/launch_background.xml b/frontend/frontend/pradtice/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000000..304732f884 --- /dev/null +++ b/frontend/frontend/pradtice/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/frontend/frontend/pradtice/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/frontend/frontend/pradtice/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000..db77bb4b7b Binary files /dev/null and b/frontend/frontend/pradtice/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/frontend/frontend/pradtice/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/frontend/frontend/pradtice/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000..17987b79bb Binary files /dev/null and b/frontend/frontend/pradtice/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/frontend/frontend/pradtice/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/frontend/frontend/pradtice/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000..09d4391482 Binary files /dev/null and b/frontend/frontend/pradtice/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/frontend/frontend/pradtice/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/frontend/frontend/pradtice/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..d5f1c8d34e Binary files /dev/null and b/frontend/frontend/pradtice/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/frontend/frontend/pradtice/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/frontend/frontend/pradtice/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000..4d6372eebd Binary files /dev/null and b/frontend/frontend/pradtice/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/frontend/frontend/pradtice/android/app/src/main/res/values-night/styles.xml b/frontend/frontend/pradtice/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000000..06952be745 --- /dev/null +++ b/frontend/frontend/pradtice/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/frontend/frontend/pradtice/android/app/src/main/res/values/styles.xml b/frontend/frontend/pradtice/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000000..cb1ef88056 --- /dev/null +++ b/frontend/frontend/pradtice/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/frontend/frontend/pradtice/android/app/src/profile/AndroidManifest.xml b/frontend/frontend/pradtice/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000000..399f6981d5 --- /dev/null +++ b/frontend/frontend/pradtice/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/frontend/frontend/pradtice/android/build.gradle b/frontend/frontend/pradtice/android/build.gradle new file mode 100644 index 0000000000..a7f386de26 --- /dev/null +++ b/frontend/frontend/pradtice/android/build.gradle @@ -0,0 +1,22 @@ +allprojects { + repositories { + google() + mavenCentral() + // Tmap의 repository 추가 +// maven { +// url = "https://devrepo.tmapadmin.com/repository/tmap-sdk-release/" +// } + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/frontend/frontend/pradtice/android/gradle.properties b/frontend/frontend/pradtice/android/gradle.properties new file mode 100644 index 0000000000..598d13fee4 --- /dev/null +++ b/frontend/frontend/pradtice/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx4G +android.useAndroidX=true +android.enableJetifier=true diff --git a/frontend/frontend/pradtice/android/gradle/wrapper/gradle-wrapper.properties b/frontend/frontend/pradtice/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..e1ca574ef0 --- /dev/null +++ b/frontend/frontend/pradtice/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip diff --git a/frontend/frontend/pradtice/android/settings.gradle b/frontend/frontend/pradtice/android/settings.gradle new file mode 100644 index 0000000000..1d6d19b7f8 --- /dev/null +++ b/frontend/frontend/pradtice/android/settings.gradle @@ -0,0 +1,26 @@ +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + } + settings.ext.flutterSdkPath = flutterSdkPath() + + includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "7.3.0" apply false + id "org.jetbrains.kotlin.android" version "1.7.10" apply false +} + +include ":app" diff --git a/frontend/frontend/pradtice/ios/.gitignore b/frontend/frontend/pradtice/ios/.gitignore new file mode 100644 index 0000000000..7a7f9873ad --- /dev/null +++ b/frontend/frontend/pradtice/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/frontend/frontend/pradtice/ios/Flutter/AppFrameworkInfo.plist b/frontend/frontend/pradtice/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000000..7c56964006 --- /dev/null +++ b/frontend/frontend/pradtice/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 + + diff --git a/frontend/frontend/pradtice/ios/Flutter/Debug.xcconfig b/frontend/frontend/pradtice/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000000..ec97fc6f30 --- /dev/null +++ b/frontend/frontend/pradtice/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/frontend/frontend/pradtice/ios/Flutter/Release.xcconfig b/frontend/frontend/pradtice/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000000..c4855bfe20 --- /dev/null +++ b/frontend/frontend/pradtice/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/frontend/frontend/pradtice/ios/Podfile b/frontend/frontend/pradtice/ios/Podfile new file mode 100644 index 0000000000..d97f17e223 --- /dev/null +++ b/frontend/frontend/pradtice/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '12.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/frontend/frontend/pradtice/ios/Runner.xcodeproj/project.pbxproj b/frontend/frontend/pradtice/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..aa9eb53348 --- /dev/null +++ b/frontend/frontend/pradtice/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,619 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 9U2RH48PC7; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 9U2RH48PC7; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 9U2RH48PC7; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/frontend/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/frontend/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..919434a625 --- /dev/null +++ b/frontend/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/frontend/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/frontend/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/frontend/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/frontend/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000..f9b0d7c5ea --- /dev/null +++ b/frontend/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/frontend/frontend/pradtice/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/frontend/frontend/pradtice/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000000..8e3ca5dfe1 --- /dev/null +++ b/frontend/frontend/pradtice/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/frontend/pradtice/ios/Runner.xcworkspace/contents.xcworkspacedata b/frontend/frontend/pradtice/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..1d526a16ed --- /dev/null +++ b/frontend/frontend/pradtice/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/frontend/frontend/pradtice/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/frontend/pradtice/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/frontend/frontend/pradtice/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/frontend/frontend/pradtice/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/frontend/frontend/pradtice/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000..f9b0d7c5ea --- /dev/null +++ b/frontend/frontend/pradtice/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/frontend/frontend/pradtice/ios/Runner/AppDelegate.swift b/frontend/frontend/pradtice/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000000..70693e4a8c --- /dev/null +++ b/frontend/frontend/pradtice/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..d36b1fab2d --- /dev/null +++ b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000..dc9ada4725 Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000000..7353c41ecf Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000000..797d452e45 Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000..6ed2d933e1 Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000000..4cd7b0099c Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000..fe730945a0 Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000000..321773cd85 Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000000..797d452e45 Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000..502f463a9b Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000..0ec3034392 Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000..0ec3034392 Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000..e9f5fea27c Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000..84ac32ae7d Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000000..8953cba090 Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000000..0467bf12aa Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000000..0bedcf2fd4 --- /dev/null +++ b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000000..9da19eacad Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000..9da19eacad Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000..9da19eacad Binary files /dev/null and b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000000..89c2725b70 --- /dev/null +++ b/frontend/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +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. \ No newline at end of file diff --git a/frontend/frontend/pradtice/ios/Runner/Base.lproj/LaunchScreen.storyboard b/frontend/frontend/pradtice/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000000..f2e259c7c9 --- /dev/null +++ b/frontend/frontend/pradtice/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/frontend/pradtice/ios/Runner/Base.lproj/Main.storyboard b/frontend/frontend/pradtice/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000000..f3c28516fb --- /dev/null +++ b/frontend/frontend/pradtice/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/frontend/pradtice/ios/Runner/Info.plist b/frontend/frontend/pradtice/ios/Runner/Info.plist new file mode 100644 index 0000000000..8976076fc6 --- /dev/null +++ b/frontend/frontend/pradtice/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Pradtice + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + pradtice + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/frontend/frontend/pradtice/ios/Runner/Runner-Bridging-Header.h b/frontend/frontend/pradtice/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000000..308a2a560b --- /dev/null +++ b/frontend/frontend/pradtice/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/frontend/frontend/pradtice/ios/RunnerTests/RunnerTests.swift b/frontend/frontend/pradtice/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000000..86a7c3b1b6 --- /dev/null +++ b/frontend/frontend/pradtice/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/frontend/frontend/pradtice/lib/GetAndroidID.dart b/frontend/frontend/pradtice/lib/GetAndroidID.dart new file mode 100644 index 0000000000..71faaf5c86 --- /dev/null +++ b/frontend/frontend/pradtice/lib/GetAndroidID.dart @@ -0,0 +1,45 @@ +import 'package:android_id/android_id.dart'; +import 'package:flutter/services.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; + + +class GetID { + static const _androidIdPlugin = AndroidId(); + String id = ''; + + GetID() { + setID().then((_) { + // GET 방식으로 서버에 전송 + SendToServer(); + print(id); + }); + } + + Future setID() async { + String AndroidID; + try { + AndroidID = await _androidIdPlugin.getId() ?? 'Unknown ID'; + } on PlatformException { + AndroidID = 'Failed to get Android ID.'; + } + id = AndroidID; + } + + Future SendToServer() async { + // URL에 파라미터를 포함하여 GET 요청을 보냅니다. + var url = Uri.parse('http://15.164.219.111:8080/checkMember?uuid=$id'); + + try { + var response = await http.get(url); + if (response.statusCode != 200) { + print("서버에 전송 실패"); + } else { + print("서버에 전송 완료"); + print(jsonDecode(response.body)); + } + } catch (e) { + print("에러 코드 : $e"); + } + } +} diff --git a/frontend/frontend/pradtice/lib/GoogleMap.dart b/frontend/frontend/pradtice/lib/GoogleMap.dart new file mode 100644 index 0000000000..fab2745fa8 --- /dev/null +++ b/frontend/frontend/pradtice/lib/GoogleMap.dart @@ -0,0 +1,99 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +class MyGoogleMap extends StatelessWidget { + @override + Widget build(BuildContext context) { + return _MapSample(); + } +} + +class _MapSample extends StatefulWidget { + @override + State<_MapSample> createState() => _MapSampleState(); +} + +class _MapSampleState extends State<_MapSample> { + Completer _controller = Completer(); + + Set _markers = {}; + + static final CameraPosition _kGooglePlex = CameraPosition( + target: LatLng(37.5271883, 126.9659283), + zoom: 14.4746, + ); + + static final CameraPosition _kLake = CameraPosition( + bearing: 192.8334901395799, + target: LatLng(37.43296265331129, -122.08832357078792), + tilt: 59.440717697143555, + zoom: 19.151926040649414); + + // 남산타워 위치 설정 + static final CameraPosition _kNamsanTower = CameraPosition( + target: LatLng(37.5511694, 126.9882266), + zoom: 14.4746, + ); + + @override + void initState() { + super.initState(); + _initializeMarkers(); + } + + void _initializeMarkers() { + _markers.add( + Marker( + markerId: MarkerId('_kGooglePlex'), + position: _kGooglePlex.target, + infoWindow: InfoWindow( + title: 'Google Plex', + snippet: 'Google Headquarters', + ), + icon: BitmapDescriptor.defaultMarker, + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: GoogleMap( + mapType: MapType.hybrid, + initialCameraPosition: _kGooglePlex, + markers: _markers, + onMapCreated: (GoogleMapController controller) { + _controller.complete(controller); + }, + ), + floatingActionButton: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + FloatingActionButton.extended( + onPressed: _goToTheLake, + label: Text('To the lake!'), + icon: Icon(Icons.directions_boat), + ), + SizedBox(width: 16), // 버튼 사이의 간격 + FloatingActionButton.extended( + onPressed: _goToNamsanTower, + label: Text('To Namsan Tower!'), + icon: Icon(Icons.landscape), + ), + ], + ), + ); + } + + Future _goToTheLake() async { + final GoogleMapController controller = await _controller.future; + controller.animateCamera(CameraUpdate.newCameraPosition(_kLake)); + } + + // 남산타워로 이동하는 함수 + Future _goToNamsanTower() async { + final GoogleMapController controller = await _controller.future; + controller.animateCamera(CameraUpdate.newCameraPosition(_kNamsanTower)); + } +} diff --git a/frontend/frontend/pradtice/lib/ObjectRecognitionMode.dart b/frontend/frontend/pradtice/lib/ObjectRecognitionMode.dart new file mode 100644 index 0000000000..71fd2fce66 --- /dev/null +++ b/frontend/frontend/pradtice/lib/ObjectRecognitionMode.dart @@ -0,0 +1,201 @@ +import 'package:flutter/material.dart'; +import 'package:pradtice/camera/recognition.dart'; +import 'package:pradtice/camera/box_widget.dart'; +import 'package:pradtice/camera/camera_settings.dart'; +import 'camera/camera_view.dart'; +import 'location_permission.dart'; +import 'package:permission_handler/permission_handler.dart'; + +class ObjectRecognitionMode extends StatefulWidget { + const ObjectRecognitionMode({Key? key}) : super(key: key); + + @override + _ObjectRecognitionModeState createState() => _ObjectRecognitionModeState(); +} + +class _ObjectRecognitionModeState extends State { + /// Results to draw bounding boxes + List? results; + + /// Realtime stats + int totalElapsedTime = 0; + + /// Scaffold Key + GlobalKey scaffoldKey = GlobalKey(); + + /// 위치 권한 설정 + MyLocation myLocation = MyLocation(); + + // 위치 추적 상태를 관리하는 새로운 변수 + bool isTrackingLocation = true; + + // UI 업데이트를 위한 콜백 함수 + Function? onUpdate; + + /// 카메라 권한 설정 + camera_Permission() async { + var status = await Permission.camera.status; + + if (status.isGranted) { + print('허락됨'); + } + else if (status.isDenied) { + print('거절됨'); + Permission.contacts.request(); + } + } + + // 위치 추적 상태를 변경하는 메소드 + void toggleLocationTracking() { + isTrackingLocation = !isTrackingLocation; + if (isTrackingLocation) { + myLocation.getMyCurrentLocation(); + } else { + print('위치 추적 종료'); + // 추가적으로 위치 추적을 종료하는 로직을 구현하세요. + } + // UI 업데이트를 위한 콜백 함수 호출 + onUpdate?.call(); + } + + @override + void initState() { + super.initState(); + if (isTrackingLocation) { + myLocation.getMyCurrentLocation(); + } + camera_Permission(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: scaffoldKey, + appBar: AppBar( + backgroundColor: Colors.black, + title: const Text( + '객체 인식 모드', + style: TextStyle( + fontWeight: FontWeight.w600, color: Colors.white, fontSize: 15), + ), + actions : [ + IconButton(onPressed: (){ toggleLocationTracking; }, icon : Icon(Icons.location_on)), + IconButton(onPressed: (){ camera_Permission(); }, icon : Icon(Icons.photo_camera)), + ] + ), + body: Stack( + children: [ + CameraView(resultsCallback, updateElapsedTimeCallback), + + /// 사진,위치 권한 아이콘 실행시 허가 기능 (미완성) + // Align( + // alignment: Alignment.bottomRight, // 하단 우측에 배치 + // child: Padding( + // padding: const EdgeInsets.all(16.0), // 여백을 주어 가장자리와의 간격을 조정 + // child: IconButton( + // icon: Icon(Icons.contacts), + // onPressed: () { + // myLocation.getMyCurrentLocation(); + // }, + // ), + // ), + // ), + + boundingBoxes(results), + Align( + alignment: Alignment.bottomCenter, + // SingleChildScrollView() -> 단일 자식만 가질수 있음 + child: SingleChildScrollView( + child: + Column( + children: [ + resultsList(results), + Padding( + padding: const EdgeInsets.all(10.0), + child: + Column( + children: [ + statsRow('이미지 추론 시간:', '$totalElapsedTime ms'), + statsRow('이미지 크기', + '${CameraSettings.inputImageSize?.width} X ${CameraSettings.inputImageSize?.height}'), + ], + ), + ) + ], + ), + ), + ), + ], + ), + ); + } + + /// Returns Stack of bounding boxes + Widget boundingBoxes(List? results) { + if (results == null) { + return Container(); + } + return Stack( + children: results + .map((e) => BoxWidget( + result: e, + )) + .toList(), + ); + } + + Widget resultsList(List? results) { + if (results == null) { + return Container(); + } + return SizedBox( + height: 120, + child: ListView.builder( + shrinkWrap: true, + physics: ClampingScrollPhysics(), + itemCount: results.length, + itemBuilder: (context, index) { + return Container( + height: 20, + child: ListTile( + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('${(index + 1)}. 객체명: ${results[index].label}', + style: TextStyle(fontSize: 13)), + Text( + '예츨확률: ${(results[index].score! * 100).toStringAsFixed(1)} %', + style: TextStyle(fontSize: 13)), + ], + ), + ), + ); + }, + ), + ); + } + + /// Callback to get inference results from [CameraView] + void resultsCallback(List results) { + setState(() { + this.results = results; + }); + } + + void updateElapsedTimeCallback(int elapsedTime) { + setState(() { + totalElapsedTime = elapsedTime; + }); + } +} + +/// Row for one Stats field +Padding statsRow(left, right) { + return Padding( + padding: const EdgeInsets.only(bottom: 10.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [Text(left), Text(right)], + ), + ); +} diff --git a/frontend/frontend/pradtice/lib/TextToSpeech.dart b/frontend/frontend/pradtice/lib/TextToSpeech.dart new file mode 100644 index 0000000000..9e008a728d --- /dev/null +++ b/frontend/frontend/pradtice/lib/TextToSpeech.dart @@ -0,0 +1,24 @@ +import 'package:flutter_tts/flutter_tts.dart'; +import 'package:flutter/material.dart'; + +class TTS{ + String message; + final FlutterTts tts = FlutterTts(); + + TTS({required this.message}){ + initialize(); + } + + void initialize() async { + await tts.setLanguage('ko-KR'); + await tts.setSpeechRate(0.3); + } + + void setMessage(String setMessage){ + message = setMessage; + } + + void speak(){ + tts.speak(message); + } +} \ No newline at end of file diff --git a/frontend/frontend/pradtice/lib/Tmap.dart b/frontend/frontend/pradtice/lib/Tmap.dart new file mode 100644 index 0000000000..2d25b22658 --- /dev/null +++ b/frontend/frontend/pradtice/lib/Tmap.dart @@ -0,0 +1,97 @@ +// import 'package:flutter/material.dart'; +// import 'package:provider/provider.dart'; +// import 'package:tmap_ui_sdk/tmap_ui_sdk.dart'; +// +// // Tmap SDK 인증 및 초기화 +// Future initTmap() async { +// try { +// // 사용자 단말의 플랫폼 버전을 획득 +// String? platformVersion = await TmapUiSdk().getPlatformVersion(); +// +// // 사용자 인증 입력 +// AuthData authData = AuthData( +// clientApiKey: "4m4ftbOA1eahz7OJQgmfDAi7P7ugSO89PeiYSEA7", // 필수 +// userKey: "", +// clientServiceName: "", +// clientID: "", +// clientDeviceId: "", +// clientAppVersion: "", +// clientApCode: "", +// ); +// +// // 사용자 인증, 초기화 +// InitResult? result = await TmapUISDKManager().initSDK(authData); +// +// if (platformVersion != null && result != null && result == InitResult.granted) { +// print("초기화 성공 : $platformVersion / $result"); +// } else { +// print("초기화 실패 : $platformVersion / $result"); +// } +// } catch (e) { +// print("error ${e.toString()}"); +// } +// } +// +// // 사용자의 차량 정보와 SDK UI의 속성을 설정하는 클래스 +// class ConfigCarModel { +// SDKConfig get normalCar => SDKConfig( +// carType: UISDKCarModel.normal, +// fuelType: UISDKFuel.gas, +// showTrafficAccident: true, +// mapTextSize: UISDKMapFontSize.small, +// nightMode: UISDKAutoNightModeType.auto, +// isUseSpeedReactMapScale: true, +// isShowTrafficInRoute: false, +// isShowExitPopupWhenStopDriving: true, +// ); +// } +// +// // 프로젝트 전역에서 사용할 Home 위젯 +// class Home extends StatelessWidget { +// const Home({Key? key}) : super(key: key); +// +// @override +// Widget build(BuildContext context) { +// return MultiProvider( +// providers: [ +// Provider(create: (context) => ConfigCarModel()), +// ], +// child: MaterialApp.router( +// title: "NAVI SDK SAMPLE", +// theme: ThemeData(primarySwatch: Colors.blue), +// debugShowCheckedModeBanner: false, +// routerConfig: _router, +// ), +// ); +// } +// } +// +// // 차량 설정 적용 +// Future setCarConfig(BuildContext context) async { +// ConfigCarModel model = context.read(); +// +// bool? result = await TmapUISDKManager().setConfigSDK(model.normalCar); +// +// return result; +// } +// +// // 경로 요청 위젯 +// TmapViewWidget getTmapViewWidget() { +// RouteRequestData data = RouteRequestData( +// source: null, // 출발지, null 일 때 SDK 내부적으로 현재위치에서 시작 +// destination: RoutePoint( +// latitude: 37.566491, +// longitude: 126.985146, +// name: "SKT Tower", +// ), // 목적지, 필수 +// routeOption: [ +// PlanningOption.recommend, +// PlanningOption.shortest, +// ], // 경로 옵션 +// wayPoints: null, // 경유지 +// safeDriving: false, // 안전 운행 +// guideWithoutPreview: false, // 선택 없이 바로 안내 +// ); +// +// return TmapViewWidget(data: data); +// } diff --git a/frontend/frontend/pradtice/lib/camera/box_widget.dart b/frontend/frontend/pradtice/lib/camera/box_widget.dart new file mode 100644 index 0000000000..d8d5a85a37 --- /dev/null +++ b/frontend/frontend/pradtice/lib/camera/box_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:pradtice/camera/recognition.dart'; + +class BoxWidget extends StatelessWidget { + final Recognition result; + // BoxWidget 생성자 + const BoxWidget({Key? key, required this.result}) : super(key: key); + @override + Widget build(BuildContext context) { + // 결과에 따라 색상을 설정 + Color color = Colors.primaries[((result.label?.length ?? 0) + + result.label!.codeUnitAt(0) + + (result.id ?? 0)) % + Colors.primaries.length]; + // Positioned 위젯을 사용하여 인식된 객체의 위치와 크기를 설정 + return Positioned( + left: result.renderLocation.left, + top: result.renderLocation.top, + width: result.renderLocation.width, + height: result.renderLocation.height, + child: Container( + width: result.renderLocation.width, + height: result.renderLocation.height, + // 경계 상자의 테두리 + decoration: BoxDecoration( + border: Border.all(color: color, width: 3), + ), + child: Align( + alignment: Alignment.topLeft, + child: FittedBox( + // 인식된 객체의 레이블과 확률 표시 + child: Container( + color: color, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text('${result.label} ${result.score!.toStringAsFixed(2)}'), + ], + ), + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/frontend/frontend/pradtice/lib/camera/camera_settings.dart b/frontend/frontend/pradtice/lib/camera/camera_settings.dart new file mode 100644 index 0000000000..437325bb37 --- /dev/null +++ b/frontend/frontend/pradtice/lib/camera/camera_settings.dart @@ -0,0 +1,17 @@ +import 'dart:ui'; + +class CameraSettings { + // 카메라 프리뷰의 가로 세로 비율을 저장하는 변수 + static double? ratio; + // 화면 크기를 저장하는 변수 + static Size? screenSize; + // 입력 이미지 크기를 저장하는 변수 + static Size? inputImageSize; + // 실제 프리뷰 크기를 계산하여 반환하는 getter + static Size get actualPreviewSize => Size( + // 화면의 너비 + screenSize?.width ?? 0, + // 화면의 너비에 비율을 곱하여 높이를 계산 + (screenSize?.width ?? 0) * (ratio ?? 0), + ); +} \ No newline at end of file diff --git a/frontend/frontend/pradtice/lib/camera/camera_view.dart b/frontend/frontend/pradtice/lib/camera/camera_view.dart new file mode 100644 index 0000000000..b9ce29e44d --- /dev/null +++ b/frontend/frontend/pradtice/lib/camera/camera_view.dart @@ -0,0 +1,143 @@ +import 'dart:isolate'; +import 'package:camera/camera.dart'; +import 'package:flutter/material.dart'; +import 'package:pradtice/camera/classifier.dart'; +import 'package:pradtice/camera/recognition.dart'; +import 'package:pradtice/camera/camera_settings.dart'; +import 'package:pradtice/camera/isolate_utils.dart'; + +//각 프레임을 추론에 전달하는 CameraView +class CameraView extends StatefulWidget { + // 결과를 반환하기 위한 콜백 함수 + final Function(List recognitions) resultsCallback; + // 추론 시간을 업데이트하기 위한 콜백 함수 + final Function(int elapsedTime) updateElapsedTimeCallback; + // CameraView 생성자 + const CameraView(this.resultsCallback, this.updateElapsedTimeCallback); + @override + _CameraViewState createState() => _CameraViewState(); +} +class _CameraViewState extends State with WidgetsBindingObserver { + // 사용 가능한 카메라 목록 + List? cameras; + // 카메라 컨트롤러 + CameraController? cameraController; + // 추론 중일 때 true + bool? predicting; + // Classifier 인스턴스 + Classifier? classifier; + // IsolateUtils 인스턴스 + IsolateUtils? isolateUtils; + @override + void initState() { + super.initState(); + initStateAsync(); + } + void initStateAsync() async { + WidgetsBinding.instance.addObserver(this); + // 새로운 Isolate를 생성 + isolateUtils = IsolateUtils(); + await isolateUtils?.start(); + // 카메라 초기화 + initializeCamera(); + // 모델 및 레이블을 로드하기 위해 Classifier 인스턴스 생성 + classifier = Classifier(); + // 초기에 predicting은 false로 설정 + predicting = false; + } + // 카메라를 초기화하고 cameraController를 설정 + void initializeCamera() async { + cameras = await availableCameras(); + // cameras[0]은 후면 카메라 + cameraController = + CameraController(cameras![0], ResolutionPreset.low, enableAudio: false); + cameraController?.initialize().then((_) async { + // onLatestImageAvailable 함수를 전달하여 각 프레임에 대한 인식을 수행 + await cameraController?.startImageStream(onLatestImageAvailable); + // 현재 카메라의 미리보기의 크기 + Size? previewSize = cameraController?.value.previewSize; + CameraSettings.inputImageSize = previewSize; + // 해당 스마트폰의 화면의 크기 + Size screenSize = MediaQuery.of(context).size; + CameraSettings.screenSize = screenSize; + //프리뷰 프레임의 너비와 화면 너비 간의 비율 + CameraSettings.ratio = screenSize.width / (previewSize?.height ?? 0); + }); + } + @override + Widget build(BuildContext context) { + // 카메라가 초기화되지 않은 경우 빈 컨테이너 반환 + if (cameraController == null || !cameraController!.value.isInitialized) { + return Container(); + } + // 카메라 프리뷰 + return AspectRatio( + //카메라 프리뷰 화면의 가로 세로 비율 + aspectRatio: 1 / cameraController!.value.aspectRatio, + child: CameraPreview(cameraController!), + ); + } + // 프레임마다 호출 + onLatestImageAvailable(CameraImage cameraImage) async { + if (classifier?.interpreter != null && classifier?.labels != null) { + // 이전 추론이 완료되지 않은 경우 반환 + if (predicting ?? false) { + return; + } + setState(() { + // 이전 추론 완료 + predicting = true; + }); + //추론 시작 시간 + var uiThreadTimeStart = DateTime.now().millisecondsSinceEpoch; + // 추론 Isolate에 전달할 데이터 + var isolateData = IsolateData(cameraImage, + classifier?.interpreter?.address ?? 0, classifier?.labels ?? []); + // 추론 결과 반환 + Map inferenceResults = await inference(isolateData); + // 추론 시간 계산 + var uiThreadInferenceElapsedTime = + DateTime.now().millisecondsSinceEpoch - uiThreadTimeStart; + // 결과를 HomeView로 전달 + widget.resultsCallback(inferenceResults["recognitions"]); + // 추론 시간 HomeView로 전달 + widget.updateElapsedTimeCallback(uiThreadInferenceElapsedTime); + // 새로운 프레임을 허용하기 위해 predicting을 false로 설정 + setState(() { + predicting = false; + }); + } + } + // 다른 Isolate에서 추론을 실행 + Future> inference(IsolateData isolateData) async { + ReceivePort responsePort = ReceivePort(); + isolateUtils?.sendPort + ?.send(isolateData..responsePort = responsePort.sendPort); + var results = await responsePort.first; + return results; + } + @override + // 앱이 일시 중지되거나 재개될 때 호출 + void didChangeAppLifecycleState(AppLifecycleState state) async { + switch (state) { + // 앱이 일시 중지되면 카메라 컨트롤러의 이미지 스트림 중지 + case AppLifecycleState.paused: + cameraController?.stopImageStream(); + break; + // 앱이 재개되면 카메라 컨트롤러의 이미지 스트림을 다시 시작 + case AppLifecycleState.resumed: + if (!cameraController!.value.isStreamingImages) { + await cameraController?.startImageStream(onLatestImageAvailable); + } + break; + default: + } + } + @override + // 앱이 화면에서 사라질 때 호출 + void dispose() { + WidgetsBinding.instance.removeObserver(this); + cameraController?.dispose(); + super.dispose(); + } +} \ No newline at end of file diff --git a/frontend/frontend/pradtice/lib/camera/classifier.dart b/frontend/frontend/pradtice/lib/camera/classifier.dart new file mode 100644 index 0000000000..7475f44935 --- /dev/null +++ b/frontend/frontend/pradtice/lib/camera/classifier.dart @@ -0,0 +1,133 @@ +import 'dart:math'; +import 'dart:ui'; +import 'package:flutter/material.dart'; +import 'package:image/image.dart' as imageLib; +import 'package:pradtice/camera/recognition.dart'; +import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_flutter_helper/tflite_flutter_helper.dart'; + +class Classifier { + // 인터프리터 및 레이블 저장 + Interpreter? _interpreter; + List? _labels; + // 모델 및 레이블 파일 이름, 입력 크기, 임계값 정의 + static const String MODEL_FILE_NAME = "detect.tflite"; + static const String LABEL_FILE_NAME = "labelmap.txt"; + static const int INPUT_SIZE = 300; + static const double THRESHOLD = 0.5; + ImageProcessor? imageProcessor; + int? padSize; + List>? _outputShapes; + List? _outputTypes; + static const int NUM_RESULTS = 10; + // Classifier 클래스 생성자 + Classifier({ + Interpreter? interpreter, + List? labels, + }) { + loadModel(interpreter: interpreter); + loadLabels(labels: labels); + } + // 머신러닝 모델 로드 + void loadModel({Interpreter? interpreter}) async { + try { + _interpreter = interpreter ?? + await Interpreter.fromAsset( + MODEL_FILE_NAME, + options: InterpreterOptions()..threads = 4, + ); + var outputTensors = _interpreter?.getOutputTensors(); + _outputShapes = []; + _outputTypes = []; + outputTensors?.forEach((tensor) { + _outputShapes?.add(tensor.shape); + _outputTypes?.add(tensor.type); + }); + } catch (e) { + print(e); + } + } + // 레이블 로드 + void loadLabels({List? labels}) async { + try { + _labels = + labels ?? await FileUtil.loadLabels("assets/" + LABEL_FILE_NAME); + } catch (e) { + print(e); + } + } + // 입력 이미지를 처리 + TensorImage getProcessedImage(TensorImage? inputImage) { + padSize = max(inputImage?.height ?? 0, inputImage?.width ?? 0); + + imageProcessor ??= ImageProcessorBuilder() + .add(ResizeWithCropOrPadOp(padSize ?? 0, padSize ?? 0)) + .add(ResizeOp(INPUT_SIZE, INPUT_SIZE, ResizeMethod.BILINEAR)) + .build(); + inputImage = imageProcessor?.process(inputImage!); + return inputImage!; + } + // 이미지를 예측하고 인식 결과를 반환 + Map? predict(imageLib.Image image) { + if (_interpreter == null) { + return null; + } + // 입력 이미지를 처리하고 예측 + TensorImage inputImage = TensorImage.fromImage(image); + inputImage = getProcessedImage(inputImage); + // 각 출력 텐서를 저장할 TensorBuffer 정의 + TensorBuffer outputLocations = TensorBufferFloat(_outputShapes![0]); + TensorBuffer outputClasses = TensorBufferFloat(_outputShapes![1]); + TensorBuffer outputScores = TensorBufferFloat(_outputShapes![2]); + TensorBuffer numLocations = TensorBufferFloat(_outputShapes![3]); + // 입력 이미지 + List inputs = [inputImage.buffer]; + // 출력에 해당하는 텐서 버퍼를 저장할 Map 정의 + Map outputs = { + 0: outputLocations.buffer, + 1: outputClasses.buffer, + 2: outputScores.buffer, + 3: numLocations.buffer, + }; + // 머신러닝 모델 실행 + _interpreter?.runForMultipleInputs(inputs, outputs); + int resultsCount = min(NUM_RESULTS, numLocations.getIntValue(0)); + int labelOffset = 1; + // 인식된 객체의 위치 변환 + List locations = BoundingBoxUtils.convert( + tensor: outputLocations, + valueIndex: [1, 0, 3, 2], + boundingBoxAxis: 2, + boundingBoxType: BoundingBoxType.BOUNDARIES, + coordinateType: CoordinateType.RATIO, + height: INPUT_SIZE, + width: INPUT_SIZE, + ); + // 인식 결과를 저장할 목록 정의 + List recognitions = []; + // 각 인식 결과를 Recognition 객체로 생성하고 목록에 추가 + for (int i = 0; i < resultsCount; i++) { + var score = outputScores.getDoubleValue(i); + var labelIndex = outputClasses.getIntValue(i) + labelOffset; + var label = _labels?.elementAt(labelIndex); + if (score > THRESHOLD) { + Rect? transformedRect = imageProcessor?.inverseTransformRect( + locations[i], + image.height, + image.width, + ); + + recognitions.add( + Recognition(i, label, score, transformedRect), + ); + } + } + // 인식 결과 반환 + return { + "recognitions": recognitions, + }; + } + // 인터프리터 및 레이블 getter + Interpreter? get interpreter => _interpreter; + List? get labels => _labels; +} \ No newline at end of file diff --git a/frontend/frontend/pradtice/lib/camera/image_utils.dart b/frontend/frontend/pradtice/lib/camera/image_utils.dart new file mode 100644 index 0000000000..6efb1f391e --- /dev/null +++ b/frontend/frontend/pradtice/lib/camera/image_utils.dart @@ -0,0 +1,65 @@ +import 'package:camera/camera.dart'; +import 'package:image/image.dart' as imageLib; + +// ImageUtils 클래스 +class ImageUtils { + // CameraImage 객체를 YUV420 형식에서 imageLib.Image(RGB 형식)으로 변환 + static imageLib.Image? convertCameraImage(CameraImage cameraImage) { + // 이미지 형식에 따라 변환 함수 호출 + if (cameraImage.format.group == ImageFormatGroup.yuv420) { + return convertYUV420ToImage(cameraImage); + } else if (cameraImage.format.group == ImageFormatGroup.bgra8888) { + return convertBGRA8888ToImage(cameraImage); + } else { + return null; + } + } + // CameraImage 객체를 BGRA8888 형식에서 imageLib.Image(RGB 형식)으로 변환 + static imageLib.Image convertBGRA8888ToImage(CameraImage cameraImage) { + imageLib.Image img = imageLib.Image.fromBytes( + cameraImage.planes[0].width ?? 0, + cameraImage.planes[0].height ?? 0, + cameraImage.planes[0].bytes, + format: imageLib.Format.bgra); + return img; + } + // CameraImage 객체를 YUV420 형식에서 imageLib.Image(RGB 형식)으로 변환 + static imageLib.Image convertYUV420ToImage(CameraImage cameraImage) { + // 이미지의 너비와 높이를 가져옴 + final int width = cameraImage.width; + final int height = cameraImage.height; + final int uvRowStride = cameraImage.planes[1].bytesPerRow; + final int uvPixelStride = cameraImage.planes[1].bytesPerPixel ?? 0; + final image = imageLib.Image(width, height); + // 모든 픽셀을 YUV 값을 RGB로 변 + for (int w = 0; w < width; w++) { + for (int h = 0; h < height; h++) { + final int uvIndex = + uvPixelStride * (w / 2).floor() + uvRowStride * (h / 2).floor(); + final int index = h * width + w; + final y = cameraImage.planes[0].bytes[index]; + final u = cameraImage.planes[1].bytes[uvIndex]; + final v = cameraImage.planes[2].bytes[uvIndex]; + + image.data[index] = ImageUtils.yuv2rgb(y, u, v); + } + } + return image; + } + // 단일 YUV 픽셀을 RGB로 변환 + static int yuv2rgb(int y, int u, int v) { + // YUV 픽셀 값을 RGB 값으로 변환 + int r = (y + v * 1436 / 1024 - 179).round(); + int g = (y - u * 46549 / 131072 + 44 - v * 93604 / 131072 + 91).round(); + int b = (y + u * 1814 / 1024 - 227).round(); + // RGB 값을 경계 [0, 255] 내에 있도록 설정 + r = r.clamp(0, 255); + g = g.clamp(0, 255); + b = b.clamp(0, 255); + // 최종적으로 변환된 RGB 값 반환 + return 0xff000000 | + ((b << 16) & 0xff0000) | + ((g << 8) & 0xff00) | + (r & 0xff); + } +} \ No newline at end of file diff --git a/frontend/frontend/pradtice/lib/camera/isolate_utils.dart b/frontend/frontend/pradtice/lib/camera/isolate_utils.dart new file mode 100644 index 0000000000..0066f07e26 --- /dev/null +++ b/frontend/frontend/pradtice/lib/camera/isolate_utils.dart @@ -0,0 +1,48 @@ +import 'dart:async'; +import 'dart:isolate'; +import 'package:camera/camera.dart'; +import 'package:image/image.dart' as imageLib; +import 'package:pradtice/camera/classifier.dart'; +import 'package:tflite_flutter/tflite_flutter.dart'; +import 'image_utils.dart'; + +class IsolateUtils { + Isolate? _isolate; + ReceivePort _receivePort = ReceivePort(); + SendPort? _sendPort; + SendPort? get sendPort => _sendPort; + // Isolate 시작 + Future start() async { + _isolate = await Isolate.spawn(entryPoint, _receivePort.sendPort); + _sendPort = await _receivePort.first; + } + // Isolate의 entryPoint 함수 + static void entryPoint(SendPort sendPort) async { + final port = ReceivePort(); + sendPort.send(port.sendPort); + // 전달받은 데이터를 사용하여 분류 및 추론 수행 + await for (final IsolateData isolateData in port) { + Classifier classifier = Classifier( + interpreter: Interpreter.fromAddress(isolateData.interpreterAddress), + labels: isolateData.labels); + imageLib.Image? image = + ImageUtils.convertCameraImage(isolateData.cameraImage); + image = imageLib.copyRotate(image!, 90); + Map? results = classifier.predict(image); + isolateData.responsePort?.send(results); + } + } +} +// Isolate 간에 전달할 데이터 class +class IsolateData { + CameraImage cameraImage; + int interpreterAddress; + List labels; + SendPort? responsePort; + + IsolateData( + this.cameraImage, + this.interpreterAddress, + this.labels, + ); +} \ No newline at end of file diff --git a/frontend/frontend/pradtice/lib/camera/recognition.dart b/frontend/frontend/pradtice/lib/camera/recognition.dart new file mode 100644 index 0000000000..d8b344fc22 --- /dev/null +++ b/frontend/frontend/pradtice/lib/camera/recognition.dart @@ -0,0 +1,57 @@ +import 'dart:math'; +import 'package:flutter/cupertino.dart'; +import 'package:pradtice/camera/camera_settings.dart'; + +class Recognition { + // 인식된 객체의 ID 저장 + final int? _id; + // 인식된 객체의 레이블 저장 + final String? _label; + // 인식된 객체의 확률(신뢰도) 저장 + final double? _score; + // 인식된 객체의 위치 저장 + final Rect? _location; + // Recognition 클래스 생성자 + Recognition( + this._id, + this._label, + this._score, [ + this._location, + ]); + // 각 변수에 대한 getter + int? get id => _id; + String? get label => _label; + double? get score => _score; + Rect? get location => _location; + // 객체의 위치를 화면에 맞게 변환하여 반환 + Rect get renderLocation { + // 카메라 설정에서 비율 값 + double? ratioX = CameraSettings.ratio; + double? ratioY = ratioX; + // 위치 정보를 변환하여 좌표로 계산 + double transLeft = max( + 0.1, + (location?.left ?? 0) * (ratioX ?? 0), + ); + double transTop = max( + 0.1, + (location?.top ?? 0) * (ratioY ?? 0), + ); + double transWidth = min( + (location?.width ?? 0) * (ratioX ?? 0), + CameraSettings.actualPreviewSize.width, + ); + double transHeight = min( + (location?.height ?? 0) * (ratioY ?? 0), + CameraSettings.actualPreviewSize.height, + ); + // 변환된 위치 정보를 생성하여 반환 + Rect transformedRect = Rect.fromLTWH( + transLeft, + transTop, + transWidth, + transHeight, + ); + return transformedRect; + } +} \ No newline at end of file diff --git a/frontend/frontend/pradtice/lib/location_permission.dart b/frontend/frontend/pradtice/lib/location_permission.dart new file mode 100644 index 0000000000..6385ce8b19 --- /dev/null +++ b/frontend/frontend/pradtice/lib/location_permission.dart @@ -0,0 +1,47 @@ +import 'dart:async'; // Timer를 사용하기 위해 필요합니다. +import 'package:geolocator/geolocator.dart'; +import 'package:permission_handler/permission_handler.dart'; + +class MyLocation { + late double latitude; + late double longitude; + + Future getMyCurrentLocation() async { + // 위치권한을 가지고 있는지 확인 + var status_position = await Permission.location.status; + + if (status_position.isGranted) { + // 권한이 있는 경우, 10초마다 위치 정보를 출력합니다. + Timer.periodic(Duration(seconds: 10), (Timer t) async { + Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high); + + latitude = position.latitude; + longitude = position.longitude; + + print("위도: $latitude , 경도: $longitude"); + }); + } else { + // 권한이 없는 경우 + print("위치 권한이 필요합니다."); + + // 위치 권한 요청 + var status_position_request = await Permission.location.request(); + + // 사용자가 권한을 허용한 경우 + if (status_position_request.isGranted) { + Timer.periodic(Duration(seconds: 10), (Timer t) async { + Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high); + + latitude = position.latitude; + longitude = position.longitude; + + print("위도: $latitude , 경도: $longitude"); + }); + } else { + // 사용자가 권한을 거부한 경우 + print("위치 권한이 거부되었습니다."); + } + } + } + +} diff --git a/frontend/frontend/pradtice/lib/main.dart b/frontend/frontend/pradtice/lib/main.dart new file mode 100644 index 0000000000..17d49cd73a --- /dev/null +++ b/frontend/frontend/pradtice/lib/main.dart @@ -0,0 +1,215 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:permission_handler/permission_handler.dart'; //권한 설정 +import 'package:geolocator/geolocator.dart'; // 위치 패키지 +import 'ObjectRecognitionMode.dart'; // 새로 만든 파일 import +import 'location_permission.dart'; // 위치 파일 import +import 'sever.dart'; // 서버 연동 파일 import +import 'package:http/http.dart' as http; // http 사용 패키지 +import 'dart:convert'; //json 변환 패키지 +import 'dart:async'; //탭 시간차 패키지 +import 'package:speech_to_text/speech_recognition_result.dart'; // 음성 인식 패키지 +import 'package:speech_to_text/speech_to_text.dart'; // stt -> tts 패키지 + +// import 'Tmap.dart'; +import 'GoogleMap.dart'; +import 'TextToSpeech.dart'; +import 'GetAndroidID.dart'; + +void main() { + runApp( + MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home : MyApp() + ) + ); +} + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MyHomePage(); + } +} + +class MyHomePage extends StatefulWidget { + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + + //sever.dart 에서의 Sever 클래스 상속 + Sever sever = Sever(); + TTS tts = TTS(message: '기본'); + + // GoogleMap.dart 에서의 GoogleMap 클래스 상속 + MyGoogleMap mygoogleMap = MyGoogleMap(); + + //앱 실행시 백그라운드 실행 + + @override + void initState() { + super.initState(); + sever.getData(); + tts.setMessage('화면을 탭하세요'); + tts.speak(); + GetID(); + } + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // _tapCount 변수를 사용하지 않고 바로 Navigator.push를 사용하여 + // 싱글 탭 이벤트 처리 시 SttTab() 호출 + Navigator.push( + context, + MaterialPageRoute(builder: (context) => SttTab()), + ); + }, + child: Scaffold( + appBar: AppBar( + title: Text("메인화면"), + ), + body: Center( + child: Text('화면을 탭하세요', style: TextStyle(fontSize: 30)), // 텍스트 사이즈 조정 + ), + + ), + ); + } +} + +class ConvenienceMode extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('편의 기능 모드'), + ), + body: Center( + child: Text('여기에 편의 기능 모드의 기능을 구현해주세요.'), + ), + ); + } +} + + +class SttTab extends StatefulWidget { + const SttTab({Key? key}) : super(key: key); + + @override + State createState() => _SttTabState(); +} + +class _SttTabState extends State { + SpeechToText _speechToText = SpeechToText(); + bool speechEnable = false; + String _lastWords = '인식된 단어'; + + @override + void initState() { + super.initState(); + _initSpeech(); + } + + void _initSpeech() async { + speechEnable = await _speechToText.initialize(); + setState(() {}); + } + + void _startListening() async { + await _speechToText.listen(onResult: _onSpeechResult); + setState(() {}); + } + + void _stopListening() async { + await _speechToText.stop(); + setState(() {}); + } + + + + void _onSpeechResult(SpeechRecognitionResult result) { + setState(() { + _lastWords = result.recognizedWords; + }); + } + + + @override + Widget build(BuildContext context) { + return Dialog( + child: Scaffold( + appBar: AppBar(title: Text('음성인식')), + body: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: Center( + child: Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('버튼을 눌러 음성인식 시작',style: TextStyle(fontSize: 20),), + Container(height: 10,), + Text(_lastWords,style: TextStyle(fontSize: 25),), + Container(height: 50,), + IconButton(onPressed: (){ + if(_speechToText.isListening){ + _stopListening(); + }else{ + _startListening(); + } + }, icon: Icon(Icons.mic,size:50),style: IconButton.styleFrom( + fixedSize: Size(200,70) + ),), + ], + + ), + ), + ), + ), + TextButton(onPressed: (){ + if(_lastWords=='보행 모드'){ + Navigator.pop(context); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => ObjectRecognitionMode()), + ); + } + else if (_lastWords == '경로 탐색 모드') { + Navigator.pop(context); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => MyGoogleMap()) + ); + } else if(_lastWords == '즐겨찾기 모드') { + Navigator.pop(context); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => ConvenienceMode()), + ); + } + else if (_lastWords == '편의 모드') { + Navigator.pop(context); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => ConvenienceMode()), + ); + } else{ + Navigator.pop(context); + } + }, child: Text('확인',style: TextStyle(fontSize: 30),),style: TextButton.styleFrom( + fixedSize: Size(200,70) + ),) + ], + ), + ), + ); + } +} diff --git a/frontend/frontend/pradtice/lib/sever.dart b/frontend/frontend/pradtice/lib/sever.dart new file mode 100644 index 0000000000..9ef849b3da --- /dev/null +++ b/frontend/frontend/pradtice/lib/sever.dart @@ -0,0 +1,44 @@ +//메인.dart에도 밑의 2개 패키지 설치 요함 +import 'package:http/http.dart' as http; // http 사용 패키지 +import 'dart:convert'; //json 변환 패키지 + +class Sever { + +// 서버 http get 함수 + getData() async { + String address = Uri.encodeComponent("서울시 강남구 역삼동"); + var result = await http.get( + Uri.parse('http://15.164.219.111:8080/test?address="도로명주소"')); + + if (result.statusCode == 200) { + print(jsonDecode(result.body)); + } else { + throw Exception('데이터 가져오기 실패'); + } + } + + + +// 서버 http post 함수 +// postData() async { +// String address = Uri.encodeComponent("서울시 강남구 역삼동"); +// var url = Uri.parse('http://15.164.219.111:8080/test'); +// var response = await http.post( +// url, +// headers: { +// "Content-Type": "application/json", +// }, +// body: jsonEncode({ +// 'address': address, +// }), +// ); +// +// if (response.statusCode == 200) { +// print(jsonDecode(response.body)); +// } else { +// throw Exception('데이터 전송 실패'); +// } +// } +} + + diff --git a/frontend/frontend/pradtice/linux/.gitignore b/frontend/frontend/pradtice/linux/.gitignore new file mode 100644 index 0000000000..d3896c9844 --- /dev/null +++ b/frontend/frontend/pradtice/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/frontend/frontend/pradtice/linux/CMakeLists.txt b/frontend/frontend/pradtice/linux/CMakeLists.txt new file mode 100644 index 0000000000..17d5f0ed4c --- /dev/null +++ b/frontend/frontend/pradtice/linux/CMakeLists.txt @@ -0,0 +1,145 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "pradtice") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.pradtice") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/frontend/frontend/pradtice/linux/flutter/CMakeLists.txt b/frontend/frontend/pradtice/linux/flutter/CMakeLists.txt new file mode 100644 index 0000000000..d5bd01648a --- /dev/null +++ b/frontend/frontend/pradtice/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/frontend/frontend/pradtice/linux/flutter/generated_plugin_registrant.cc b/frontend/frontend/pradtice/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000000..52a5938881 --- /dev/null +++ b/frontend/frontend/pradtice/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) tflite_flutter_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "TfliteFlutterPlugin"); + tflite_flutter_plugin_register_with_registrar(tflite_flutter_registrar); +} diff --git a/frontend/frontend/pradtice/linux/flutter/generated_plugin_registrant.h b/frontend/frontend/pradtice/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000000..e0f0a47bc0 --- /dev/null +++ b/frontend/frontend/pradtice/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/frontend/frontend/pradtice/linux/flutter/generated_plugins.cmake b/frontend/frontend/pradtice/linux/flutter/generated_plugins.cmake new file mode 100644 index 0000000000..2985a20153 --- /dev/null +++ b/frontend/frontend/pradtice/linux/flutter/generated_plugins.cmake @@ -0,0 +1,24 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + tflite_flutter +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/frontend/frontend/pradtice/linux/main.cc b/frontend/frontend/pradtice/linux/main.cc new file mode 100644 index 0000000000..e7c5c54370 --- /dev/null +++ b/frontend/frontend/pradtice/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/frontend/frontend/pradtice/linux/my_application.cc b/frontend/frontend/pradtice/linux/my_application.cc new file mode 100644 index 0000000000..d7b9740fec --- /dev/null +++ b/frontend/frontend/pradtice/linux/my_application.cc @@ -0,0 +1,124 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "pradtice"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "pradtice"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/frontend/frontend/pradtice/linux/my_application.h b/frontend/frontend/pradtice/linux/my_application.h new file mode 100644 index 0000000000..72271d5e41 --- /dev/null +++ b/frontend/frontend/pradtice/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/frontend/frontend/pradtice/macos/.gitignore b/frontend/frontend/pradtice/macos/.gitignore new file mode 100644 index 0000000000..746adbb6b9 --- /dev/null +++ b/frontend/frontend/pradtice/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/frontend/frontend/pradtice/macos/Flutter/Flutter-Debug.xcconfig b/frontend/frontend/pradtice/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000000..4b81f9b2d2 --- /dev/null +++ b/frontend/frontend/pradtice/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/frontend/frontend/pradtice/macos/Flutter/Flutter-Release.xcconfig b/frontend/frontend/pradtice/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000000..5caa9d1579 --- /dev/null +++ b/frontend/frontend/pradtice/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/frontend/frontend/pradtice/macos/Flutter/GeneratedPluginRegistrant.swift b/frontend/frontend/pradtice/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 0000000000..f92403ba0d --- /dev/null +++ b/frontend/frontend/pradtice/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,18 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import flutter_tts +import geolocator_apple +import path_provider_foundation +import speech_to_text_macos + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FlutterTtsPlugin.register(with: registry.registrar(forPlugin: "FlutterTtsPlugin")) + GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SpeechToTextMacosPlugin.register(with: registry.registrar(forPlugin: "SpeechToTextMacosPlugin")) +} diff --git a/frontend/frontend/pradtice/macos/Podfile b/frontend/frontend/pradtice/macos/Podfile new file mode 100644 index 0000000000..c795730db8 --- /dev/null +++ b/frontend/frontend/pradtice/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/frontend/frontend/pradtice/macos/Runner.xcodeproj/project.pbxproj b/frontend/frontend/pradtice/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..4893b1ee34 --- /dev/null +++ b/frontend/frontend/pradtice/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,705 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* pradtice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "pradtice.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* pradtice.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* pradtice.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pradtice.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/pradtice"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pradtice.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/pradtice"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pradtice.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/pradtice"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/frontend/frontend/pradtice/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/frontend/pradtice/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/frontend/frontend/pradtice/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/frontend/frontend/pradtice/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/frontend/frontend/pradtice/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000000..869df84779 --- /dev/null +++ b/frontend/frontend/pradtice/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/frontend/pradtice/macos/Runner.xcworkspace/contents.xcworkspacedata b/frontend/frontend/pradtice/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..1d526a16ed --- /dev/null +++ b/frontend/frontend/pradtice/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/frontend/frontend/pradtice/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/frontend/pradtice/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/frontend/frontend/pradtice/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/frontend/frontend/pradtice/macos/Runner/AppDelegate.swift b/frontend/frontend/pradtice/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000000..d53ef64377 --- /dev/null +++ b/frontend/frontend/pradtice/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..a2ec33f19f --- /dev/null +++ b/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000000..82b6f9d9a3 Binary files /dev/null and b/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000000..13b35eba55 Binary files /dev/null and b/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000000..0a3f5fa40f Binary files /dev/null and b/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 0000000000..bdb57226d5 Binary files /dev/null and b/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 0000000000..f083318e09 Binary files /dev/null and b/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 0000000000..326c0e72c9 Binary files /dev/null and b/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000000..2f1632cfdd Binary files /dev/null and b/frontend/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/frontend/frontend/pradtice/macos/Runner/Base.lproj/MainMenu.xib b/frontend/frontend/pradtice/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 0000000000..80e867a4e0 --- /dev/null +++ b/frontend/frontend/pradtice/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/frontend/pradtice/macos/Runner/Configs/AppInfo.xcconfig b/frontend/frontend/pradtice/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000000..b64656ea1e --- /dev/null +++ b/frontend/frontend/pradtice/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = pradtice + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2024 com.example. All rights reserved. diff --git a/frontend/frontend/pradtice/macos/Runner/Configs/Debug.xcconfig b/frontend/frontend/pradtice/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000000..36b0fd9464 --- /dev/null +++ b/frontend/frontend/pradtice/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/frontend/frontend/pradtice/macos/Runner/Configs/Release.xcconfig b/frontend/frontend/pradtice/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000000..dff4f49561 --- /dev/null +++ b/frontend/frontend/pradtice/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/frontend/frontend/pradtice/macos/Runner/Configs/Warnings.xcconfig b/frontend/frontend/pradtice/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000000..42bcbf4780 --- /dev/null +++ b/frontend/frontend/pradtice/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/frontend/frontend/pradtice/macos/Runner/DebugProfile.entitlements b/frontend/frontend/pradtice/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000000..dddb8a30c8 --- /dev/null +++ b/frontend/frontend/pradtice/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/frontend/frontend/pradtice/macos/Runner/Info.plist b/frontend/frontend/pradtice/macos/Runner/Info.plist new file mode 100644 index 0000000000..4789daa6a4 --- /dev/null +++ b/frontend/frontend/pradtice/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/frontend/frontend/pradtice/macos/Runner/MainFlutterWindow.swift b/frontend/frontend/pradtice/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000000..3cc05eb234 --- /dev/null +++ b/frontend/frontend/pradtice/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/frontend/frontend/pradtice/macos/Runner/Release.entitlements b/frontend/frontend/pradtice/macos/Runner/Release.entitlements new file mode 100644 index 0000000000..852fa1a472 --- /dev/null +++ b/frontend/frontend/pradtice/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/frontend/frontend/pradtice/macos/RunnerTests/RunnerTests.swift b/frontend/frontend/pradtice/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000000..5418c9f539 --- /dev/null +++ b/frontend/frontend/pradtice/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import FlutterMacOS +import Cocoa +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/frontend/frontend/pradtice/pubspec.lock b/frontend/frontend/pradtice/pubspec.lock new file mode 100644 index 0000000000..b28b0cd141 --- /dev/null +++ b/frontend/frontend/pradtice/pubspec.lock @@ -0,0 +1,924 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + url: "https://pub.dev" + source: hosted + version: "67.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + url: "https://pub.dev" + source: hosted + version: "6.4.1" + android_id: + dependency: "direct main" + description: + name: android_id + sha256: "5c2d3a259afcd173dbe367ba452817bd530c4df75d251d652c69b8d3c8ac0d36" + url: "https://pub.dev" + source: hosted + version: "0.3.6" + archive: + dependency: transitive + description: + name: archive + sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" + url: "https://pub.dev" + source: hosted + version: "3.4.10" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + camera: + dependency: "direct dev" + description: + path: "packages/camera/camera" + ref: "9e46048ad2e1f085c1e8f6c77391fa52025e681f" + resolved-ref: "9e46048ad2e1f085c1e8f6c77391fa52025e681f" + url: "https://github.com/flutter/plugins" + source: git + version: "0.9.4+2" + camera_platform_interface: + dependency: transitive + description: + name: camera_platform_interface + sha256: a250314a48ea337b35909a4c9d5416a208d736dcb01d0b02c6af122be66660b0 + url: "https://pub.dev" + source: hosted + version: "2.7.4" + camera_web: + dependency: transitive + description: + name: camera_web + sha256: "18cdbee5441e9a6fb129fdd9b68a06d1b8c5236932ba97d5faeaefe80db2e5bd" + url: "https://pub.dev" + source: hosted + version: "0.2.1+6" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" + url: "https://pub.dev" + source: hosted + version: "1.7.2" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" + url: "https://pub.dev" + source: hosted + version: "0.3.4+1" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + csslib: + dependency: transitive + description: + name: csslib + sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d + url: "https://pub.dev" + source: hosted + version: "1.0.6" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 + url: "https://pub.dev" + source: hosted + version: "3.0.1" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da + url: "https://pub.dev" + source: hosted + version: "2.0.17" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_tts: + dependency: "direct main" + description: + name: flutter_tts + sha256: cbb3fd43b946e62398560235469e6113e4fe26c40eab1b7cb5e7c417503fb3a8 + url: "https://pub.dev" + source: hosted + version: "3.8.5" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + geolocator: + dependency: "direct main" + description: + name: geolocator + sha256: "5c496b46e245d006760e643cedde7c9fa785a34391b5eca857a46358f9bde02b" + url: "https://pub.dev" + source: hosted + version: "8.2.1" + geolocator_android: + dependency: transitive + description: + name: geolocator_android + sha256: "3fa9215caf1e4463adbdf1f21b07fdcb9bc2af2ef1df3715a52376b87bebb087" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + sha256: "2f2d4ee16c4df269e93c0e382be075cc01d5db6703c3196e4af20a634fe49ef4" + url: "https://pub.dev" + source: hosted + version: "2.3.6" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + sha256: "009a21c4bc2761e58dccf07c24f219adaebe0ff707abdfd40b0a763d4003fab9" + url: "https://pub.dev" + source: hosted + version: "4.2.2" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + sha256: "102e7da05b48ca6bf0a5bda0010f886b171d1a08059f01bfe02addd0175ebece" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + geolocator_windows: + dependency: transitive + description: + name: geolocator_windows + sha256: "4f4218f122a6978d0ad655fa3541eea74c67417440b09f0657238810d5af6bdc" + url: "https://pub.dev" + source: hosted + version: "0.1.3" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + google_maps: + dependency: transitive + description: + name: google_maps + sha256: "47eef3836b49bb030d5cb3afc60b8451408bf34cf753e571b645d6529eb4251a" + url: "https://pub.dev" + source: hosted + version: "7.1.0" + google_maps_flutter: + dependency: "direct main" + description: + name: google_maps_flutter + sha256: "982c2e22ec78d32701bfbd351311e8579a4952035381ac66462c0af11003107b" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + google_maps_flutter_android: + dependency: transitive + description: + name: google_maps_flutter_android + sha256: "256b3c974e415bd17555ceff76a5d0badd2cbfd29febfc23070993358f639550" + url: "https://pub.dev" + source: hosted + version: "2.7.0" + google_maps_flutter_ios: + dependency: transitive + description: + name: google_maps_flutter_ios + sha256: "6c50bce26ff73079b4401de5bfe77e89d89138897b9dcc6bdfbc7ada842f2bc1" + url: "https://pub.dev" + source: hosted + version: "2.5.2" + google_maps_flutter_platform_interface: + dependency: transitive + description: + name: google_maps_flutter_platform_interface + sha256: "167af879da4d004cd58771f1469b91dcc3b9b0a2c5334cc6bf71fd41d4b35403" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + google_maps_flutter_web: + dependency: transitive + description: + name: google_maps_flutter_web + sha256: eef2488eae840bc4d2b7d5210e26707c64fc2947a9d6f83d83e13bd01509b07d + url: "https://pub.dev" + source: hosted + version: "0.5.6+1" + html: + dependency: transitive + description: + name: html + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" + http: + dependency: "direct main" + description: + name: http + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.dev" + source: hosted + version: "0.13.6" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + image: + dependency: "direct dev" + description: + name: image + sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6" + url: "https://pub.dev" + source: hosted + version: "3.3.0" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + js_wrapping: + dependency: transitive + description: + name: js_wrapping + sha256: e385980f7c76a8c1c9a560dfb623b890975841542471eade630b2871d243851c + url: "https://pub.dev" + source: hosted + version: "0.7.4" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + url: "https://pub.dev" + source: hosted + version: "0.8.0" + meta: + dependency: transitive + description: + name: meta + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + mime: + dependency: transitive + description: + name: mime + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + pedantic: + dependency: transitive + description: + name: pedantic + sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "4356882e9abf51aa0d56e8fb886e0d6162719f2310dd71f0b8fa7f34908b128d" + url: "https://pub.dev" + source: hosted + version: "8.3.0" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: "6760eb5ef34589224771010805bea6054ad28453906936f843a8cc4d3a55c4a4" + url: "https://pub.dev" + source: hosted + version: "3.12.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + platform: + dependency: transitive + description: + name: platform + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + url: "https://pub.dev" + source: hosted + version: "3.1.4" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" + url: "https://pub.dev" + source: hosted + version: "3.7.4" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + provider: + dependency: "direct main" + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + quiver: + dependency: transitive + description: + name: quiver + sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 + url: "https://pub.dev" + source: hosted + version: "3.2.1" + sanitize_html: + dependency: transitive + description: + name: sanitize_html + sha256: "12669c4a913688a26555323fb9cec373d8f9fbe091f2d01c40c723b33caa8989" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + speech_to_text: + dependency: "direct main" + description: + name: speech_to_text + sha256: "57fef1d41bdebe298e84842c89bb4ac91f31cdbec7830c8cb1fc6b91d03abd42" + url: "https://pub.dev" + source: hosted + version: "6.6.0" + speech_to_text_macos: + dependency: transitive + description: + name: speech_to_text_macos + sha256: e685750f7542fcaa087a5396ee471e727ec648bf681f4da83c84d086322173f6 + url: "https://pub.dev" + source: hosted + version: "1.1.0" + speech_to_text_platform_interface: + dependency: transitive + description: + name: speech_to_text_platform_interface + sha256: a0df1a907091ea09880077dc25aae02af9f79811264e6e97ddb08639b7f771c2 + url: "https://pub.dev" + source: hosted + version: "2.2.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test: + dependency: "direct main" + description: + name: test + sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f + url: "https://pub.dev" + source: hosted + version: "1.24.9" + test_api: + dependency: transitive + description: + name: test_api + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + url: "https://pub.dev" + source: hosted + version: "0.6.1" + test_core: + dependency: transitive + description: + name: test_core + sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a + url: "https://pub.dev" + source: hosted + version: "0.5.9" + tflite_flutter: + dependency: "direct dev" + description: + name: tflite_flutter + sha256: "88b203c6efd7f4269aa137ef31e760d53e6639e60cd17bb86602462f72d4176b" + url: "https://pub.dev" + source: hosted + version: "0.9.5" + tflite_flutter_helper: + dependency: "direct dev" + description: + name: tflite_flutter_helper + sha256: acda0ca6d9ff36051cd45d32e0f6e4979c9d37d5b599d1f1a2900c14c708ed55 + url: "https://pub.dev" + source: hosted + version: "0.2.1" + tmap_ui_sdk: + dependency: "direct main" + description: + path: "." + ref: "1.0.26" + resolved-ref: eda927f4e4380be79b153d37698c5daf9cbcb974 + url: "https://github.com/TmapSDK/TmapUI_FlutterSDK.git" + source: git + version: "1.0.26" + tuple: + dependency: transitive + description: + name: tuple + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" + source: hosted + version: "2.0.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.dev" + source: hosted + version: "13.0.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: "1d8e795e2a8b3730c41b8a98a2dff2e0fb57ae6f0764a1c46ec5915387d257b2" + url: "https://pub.dev" + source: hosted + version: "2.4.4" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + win32: + dependency: transitive + description: + name: win32 + sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c" + url: "https://pub.dev" + source: hosted + version: "4.1.4" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + url: "https://pub.dev" + source: hosted + version: "1.0.4" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.19.0" diff --git a/frontend/frontend/pradtice/pubspec.yaml b/frontend/frontend/pradtice/pubspec.yaml new file mode 100644 index 0000000000..f2b041c71e --- /dev/null +++ b/frontend/frontend/pradtice/pubspec.yaml @@ -0,0 +1,116 @@ +name: pradtice +description: "A new Flutter project." +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: '>=3.3.0 <4.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + speech_to_text: ^6.3.0 + flutter_tts : ^3.6.0 + android_id : ^0.3.2 + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.6 + permission_handler: ^8.3.0 + geolocator: ^8.1.1 + google_maps_flutter: ^2.5.3 + provider: ^6.0.3 + +# tmap_ui_sdk: +# git: +# url: https://github.com/TmapSDK/TmapUI_FlutterSDK.git +# ref: 1.0.26 # version. git tag name + + http: ^0.13.4 + test: ^1.24.9 + + +dev_dependencies: + flutter_test: + sdk: flutter + + camera: + git: + url: https://github.com/flutter/plugins + path: packages/camera/camera + ref: 9e46048ad2e1f085c1e8f6c77391fa52025e681f + + tflite_flutter: ^0.9.1 + tflite_flutter_helper: ^0.2.1 + image: ^3.3.0 + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^3.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/frontend/frontend/pradtice/test/widget_test.dart b/frontend/frontend/pradtice/test/widget_test.dart new file mode 100644 index 0000000000..5d16f3e4e6 --- /dev/null +++ b/frontend/frontend/pradtice/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:pradtice/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget( MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/frontend/frontend/pradtice/web/favicon.png b/frontend/frontend/pradtice/web/favicon.png new file mode 100644 index 0000000000..8aaa46ac1a Binary files /dev/null and b/frontend/frontend/pradtice/web/favicon.png differ diff --git a/frontend/frontend/pradtice/web/icons/Icon-192.png b/frontend/frontend/pradtice/web/icons/Icon-192.png new file mode 100644 index 0000000000..b749bfef07 Binary files /dev/null and b/frontend/frontend/pradtice/web/icons/Icon-192.png differ diff --git a/frontend/frontend/pradtice/web/icons/Icon-512.png b/frontend/frontend/pradtice/web/icons/Icon-512.png new file mode 100644 index 0000000000..88cfd48dff Binary files /dev/null and b/frontend/frontend/pradtice/web/icons/Icon-512.png differ diff --git a/frontend/frontend/pradtice/web/icons/Icon-maskable-192.png b/frontend/frontend/pradtice/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000000..eb9b4d76e5 Binary files /dev/null and b/frontend/frontend/pradtice/web/icons/Icon-maskable-192.png differ diff --git a/frontend/frontend/pradtice/web/icons/Icon-maskable-512.png b/frontend/frontend/pradtice/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000000..d69c56691f Binary files /dev/null and b/frontend/frontend/pradtice/web/icons/Icon-maskable-512.png differ diff --git a/frontend/frontend/pradtice/web/index.html b/frontend/frontend/pradtice/web/index.html new file mode 100644 index 0000000000..faaddc7b9f --- /dev/null +++ b/frontend/frontend/pradtice/web/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + pradtice + + + + + + + + + + diff --git a/frontend/frontend/pradtice/web/manifest.json b/frontend/frontend/pradtice/web/manifest.json new file mode 100644 index 0000000000..7a991464ed --- /dev/null +++ b/frontend/frontend/pradtice/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "pradtice", + "short_name": "pradtice", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/frontend/frontend/pradtice/windows/.gitignore b/frontend/frontend/pradtice/windows/.gitignore new file mode 100644 index 0000000000..d492d0d98c --- /dev/null +++ b/frontend/frontend/pradtice/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/frontend/frontend/pradtice/windows/CMakeLists.txt b/frontend/frontend/pradtice/windows/CMakeLists.txt new file mode 100644 index 0000000000..b72d015bcf --- /dev/null +++ b/frontend/frontend/pradtice/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(pradtice LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "pradtice") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/frontend/frontend/pradtice/windows/flutter/CMakeLists.txt b/frontend/frontend/pradtice/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000000..903f4899d6 --- /dev/null +++ b/frontend/frontend/pradtice/windows/flutter/CMakeLists.txt @@ -0,0 +1,109 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/frontend/frontend/pradtice/windows/flutter/generated_plugin_registrant.cc b/frontend/frontend/pradtice/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000000..992f02b6f5 --- /dev/null +++ b/frontend/frontend/pradtice/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,17 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + FlutterTtsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterTtsPlugin")); + GeolocatorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("GeolocatorWindows")); +} diff --git a/frontend/frontend/pradtice/windows/flutter/generated_plugin_registrant.h b/frontend/frontend/pradtice/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000000..dc139d85a9 --- /dev/null +++ b/frontend/frontend/pradtice/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/frontend/frontend/pradtice/windows/flutter/generated_plugins.cmake b/frontend/frontend/pradtice/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000000..79d9239607 --- /dev/null +++ b/frontend/frontend/pradtice/windows/flutter/generated_plugins.cmake @@ -0,0 +1,25 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + flutter_tts + geolocator_windows +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/frontend/frontend/pradtice/windows/runner/CMakeLists.txt b/frontend/frontend/pradtice/windows/runner/CMakeLists.txt new file mode 100644 index 0000000000..394917c053 --- /dev/null +++ b/frontend/frontend/pradtice/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/frontend/frontend/pradtice/windows/runner/Runner.rc b/frontend/frontend/pradtice/windows/runner/Runner.rc new file mode 100644 index 0000000000..fe27e475f9 --- /dev/null +++ b/frontend/frontend/pradtice/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "pradtice" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "pradtice" "\0" + VALUE "LegalCopyright", "Copyright (C) 2024 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "pradtice.exe" "\0" + VALUE "ProductName", "pradtice" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/frontend/frontend/pradtice/windows/runner/flutter_window.cpp b/frontend/frontend/pradtice/windows/runner/flutter_window.cpp new file mode 100644 index 0000000000..955ee3038f --- /dev/null +++ b/frontend/frontend/pradtice/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/frontend/frontend/pradtice/windows/runner/flutter_window.h b/frontend/frontend/pradtice/windows/runner/flutter_window.h new file mode 100644 index 0000000000..6da0652f05 --- /dev/null +++ b/frontend/frontend/pradtice/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/frontend/frontend/pradtice/windows/runner/main.cpp b/frontend/frontend/pradtice/windows/runner/main.cpp new file mode 100644 index 0000000000..e7c10cb869 --- /dev/null +++ b/frontend/frontend/pradtice/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"pradtice", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/frontend/frontend/pradtice/windows/runner/resource.h b/frontend/frontend/pradtice/windows/runner/resource.h new file mode 100644 index 0000000000..66a65d1e4a --- /dev/null +++ b/frontend/frontend/pradtice/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/frontend/frontend/pradtice/windows/runner/resources/app_icon.ico b/frontend/frontend/pradtice/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000000..c04e20caf6 Binary files /dev/null and b/frontend/frontend/pradtice/windows/runner/resources/app_icon.ico differ diff --git a/frontend/frontend/pradtice/windows/runner/runner.exe.manifest b/frontend/frontend/pradtice/windows/runner/runner.exe.manifest new file mode 100644 index 0000000000..a42ea7687c --- /dev/null +++ b/frontend/frontend/pradtice/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/frontend/frontend/pradtice/windows/runner/utils.cpp b/frontend/frontend/pradtice/windows/runner/utils.cpp new file mode 100644 index 0000000000..b2b08734db --- /dev/null +++ b/frontend/frontend/pradtice/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length <= 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/frontend/frontend/pradtice/windows/runner/utils.h b/frontend/frontend/pradtice/windows/runner/utils.h new file mode 100644 index 0000000000..3879d54755 --- /dev/null +++ b/frontend/frontend/pradtice/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/frontend/frontend/pradtice/windows/runner/win32_window.cpp b/frontend/frontend/pradtice/windows/runner/win32_window.cpp new file mode 100644 index 0000000000..60608d0fe5 --- /dev/null +++ b/frontend/frontend/pradtice/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/frontend/frontend/pradtice/windows/runner/win32_window.h b/frontend/frontend/pradtice/windows/runner/win32_window.h new file mode 100644 index 0000000000..e901dde684 --- /dev/null +++ b/frontend/frontend/pradtice/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/frontend/pradtice/.gitignore b/frontend/pradtice/.gitignore new file mode 100644 index 0000000000..29a3a5017f --- /dev/null +++ b/frontend/pradtice/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/frontend/pradtice/.metadata b/frontend/pradtice/.metadata new file mode 100644 index 0000000000..8629a4e186 --- /dev/null +++ b/frontend/pradtice/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "abb292a07e20d696c4568099f918f6c5f330e6b0" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + - platform: android + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + - platform: ios + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + - platform: linux + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + - platform: macos + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + - platform: web + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + - platform: windows + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/frontend/pradtice/README.md b/frontend/pradtice/README.md new file mode 100644 index 0000000000..92331de053 --- /dev/null +++ b/frontend/pradtice/README.md @@ -0,0 +1,16 @@ +# pradtice + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/frontend/pradtice/analysis_options.yaml b/frontend/pradtice/analysis_options.yaml new file mode 100644 index 0000000000..0d2902135c --- /dev/null +++ b/frontend/pradtice/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/frontend/pradtice/android/.gitignore b/frontend/pradtice/android/.gitignore new file mode 100644 index 0000000000..6f568019d3 --- /dev/null +++ b/frontend/pradtice/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/frontend/pradtice/android/app/build.gradle b/frontend/pradtice/android/app/build.gradle new file mode 100644 index 0000000000..b849fd46f4 --- /dev/null +++ b/frontend/pradtice/android/app/build.gradle @@ -0,0 +1,78 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +android { + namespace "com.example.pradtice" + compileSdk flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.pradtice" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. + minSdkVersion 24 + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } + + dataBinding { + enabled = true + } + +aaptOptions { + noCompress 'tflite' + noCompress 'lite' + } +} + +flutter { + source '../..' +} + +dependencies { + implementation 'com.google.android.material:material:1.8.0' +} \ No newline at end of file diff --git a/frontend/pradtice/android/app/libs/tmap-sdk-1.2.aar b/frontend/pradtice/android/app/libs/tmap-sdk-1.2.aar new file mode 100644 index 0000000000..15fc2ffc11 Binary files /dev/null and b/frontend/pradtice/android/app/libs/tmap-sdk-1.2.aar differ diff --git a/frontend/pradtice/android/app/libs/vsm-tmap-sdk-v2-android-1.6.60.aar b/frontend/pradtice/android/app/libs/vsm-tmap-sdk-v2-android-1.6.60.aar new file mode 100644 index 0000000000..3f608eb4f6 Binary files /dev/null and b/frontend/pradtice/android/app/libs/vsm-tmap-sdk-v2-android-1.6.60.aar differ diff --git a/frontend/pradtice/android/app/src/debug/AndroidManifest.xml b/frontend/pradtice/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000000..399f6981d5 --- /dev/null +++ b/frontend/pradtice/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/frontend/pradtice/android/app/src/main/AndroidManifest.xml b/frontend/pradtice/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..7d459e21a3 --- /dev/null +++ b/frontend/pradtice/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/pradtice/android/app/src/main/kotlin/com/example/pradtice/MainActivity.kt b/frontend/pradtice/android/app/src/main/kotlin/com/example/pradtice/MainActivity.kt new file mode 100644 index 0000000000..2c30c51a9b --- /dev/null +++ b/frontend/pradtice/android/app/src/main/kotlin/com/example/pradtice/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.pradtice + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() diff --git a/frontend/pradtice/android/app/src/main/res/drawable-v21/launch_background.xml b/frontend/pradtice/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000000..f74085f3f6 --- /dev/null +++ b/frontend/pradtice/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/frontend/pradtice/android/app/src/main/res/drawable/launch_background.xml b/frontend/pradtice/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000000..304732f884 --- /dev/null +++ b/frontend/pradtice/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-hdpi/eye_u.png b/frontend/pradtice/android/app/src/main/res/mipmap-hdpi/eye_u.png new file mode 100644 index 0000000000..6cba4a90ee Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-hdpi/eye_u.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-hdpi/eye_u_background.png b/frontend/pradtice/android/app/src/main/res/mipmap-hdpi/eye_u_background.png new file mode 100644 index 0000000000..5d3e0f5b46 Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-hdpi/eye_u_background.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-hdpi/eye_u_foreground.png b/frontend/pradtice/android/app/src/main/res/mipmap-hdpi/eye_u_foreground.png new file mode 100644 index 0000000000..b2838c63ad Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-hdpi/eye_u_foreground.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-hdpi/eye_u_monochrome.png b/frontend/pradtice/android/app/src/main/res/mipmap-hdpi/eye_u_monochrome.png new file mode 100644 index 0000000000..7739429e8a Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-hdpi/eye_u_monochrome.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-mdpi/eye_u.png b/frontend/pradtice/android/app/src/main/res/mipmap-mdpi/eye_u.png new file mode 100644 index 0000000000..5ae0ad85f1 Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-mdpi/eye_u.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-mdpi/eye_u_background.png b/frontend/pradtice/android/app/src/main/res/mipmap-mdpi/eye_u_background.png new file mode 100644 index 0000000000..08dd3ef270 Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-mdpi/eye_u_background.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-mdpi/eye_u_foreground.png b/frontend/pradtice/android/app/src/main/res/mipmap-mdpi/eye_u_foreground.png new file mode 100644 index 0000000000..3926eb7db5 Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-mdpi/eye_u_foreground.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-mdpi/eye_u_monochrome.png b/frontend/pradtice/android/app/src/main/res/mipmap-mdpi/eye_u_monochrome.png new file mode 100644 index 0000000000..e36266a347 Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-mdpi/eye_u_monochrome.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-xhdpi/eye_u.png b/frontend/pradtice/android/app/src/main/res/mipmap-xhdpi/eye_u.png new file mode 100644 index 0000000000..ab7c54925a Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-xhdpi/eye_u.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-xhdpi/eye_u_background.png b/frontend/pradtice/android/app/src/main/res/mipmap-xhdpi/eye_u_background.png new file mode 100644 index 0000000000..f3203a780e Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-xhdpi/eye_u_background.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-xhdpi/eye_u_foreground.png b/frontend/pradtice/android/app/src/main/res/mipmap-xhdpi/eye_u_foreground.png new file mode 100644 index 0000000000..2b394d06e5 Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-xhdpi/eye_u_foreground.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-xhdpi/eye_u_monochrome.png b/frontend/pradtice/android/app/src/main/res/mipmap-xhdpi/eye_u_monochrome.png new file mode 100644 index 0000000000..50a8ae01eb Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-xhdpi/eye_u_monochrome.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-xxhdpi/eye_u.png b/frontend/pradtice/android/app/src/main/res/mipmap-xxhdpi/eye_u.png new file mode 100644 index 0000000000..b0504034ff Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-xxhdpi/eye_u.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-xxhdpi/eye_u_background.png b/frontend/pradtice/android/app/src/main/res/mipmap-xxhdpi/eye_u_background.png new file mode 100644 index 0000000000..1fe1035e0b Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-xxhdpi/eye_u_background.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-xxhdpi/eye_u_foreground.png b/frontend/pradtice/android/app/src/main/res/mipmap-xxhdpi/eye_u_foreground.png new file mode 100644 index 0000000000..203aff6cbf Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-xxhdpi/eye_u_foreground.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-xxhdpi/eye_u_monochrome.png b/frontend/pradtice/android/app/src/main/res/mipmap-xxhdpi/eye_u_monochrome.png new file mode 100644 index 0000000000..08d7ca87cb Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-xxhdpi/eye_u_monochrome.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-xxxhdpi/eye_u.png b/frontend/pradtice/android/app/src/main/res/mipmap-xxxhdpi/eye_u.png new file mode 100644 index 0000000000..7e44eac873 Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-xxxhdpi/eye_u.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-xxxhdpi/eye_u_background.png b/frontend/pradtice/android/app/src/main/res/mipmap-xxxhdpi/eye_u_background.png new file mode 100644 index 0000000000..669864c17b Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-xxxhdpi/eye_u_background.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-xxxhdpi/eye_u_foreground.png b/frontend/pradtice/android/app/src/main/res/mipmap-xxxhdpi/eye_u_foreground.png new file mode 100644 index 0000000000..0ab18e78ba Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-xxxhdpi/eye_u_foreground.png differ diff --git a/frontend/pradtice/android/app/src/main/res/mipmap-xxxhdpi/eye_u_monochrome.png b/frontend/pradtice/android/app/src/main/res/mipmap-xxxhdpi/eye_u_monochrome.png new file mode 100644 index 0000000000..9219710ebd Binary files /dev/null and b/frontend/pradtice/android/app/src/main/res/mipmap-xxxhdpi/eye_u_monochrome.png differ diff --git a/frontend/pradtice/android/app/src/main/res/values-night/styles.xml b/frontend/pradtice/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000000..06952be745 --- /dev/null +++ b/frontend/pradtice/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/frontend/pradtice/android/app/src/main/res/values/styles.xml b/frontend/pradtice/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000000..cb1ef88056 --- /dev/null +++ b/frontend/pradtice/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/frontend/pradtice/android/app/src/profile/AndroidManifest.xml b/frontend/pradtice/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000000..399f6981d5 --- /dev/null +++ b/frontend/pradtice/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/frontend/pradtice/android/build.gradle b/frontend/pradtice/android/build.gradle new file mode 100644 index 0000000000..a7f386de26 --- /dev/null +++ b/frontend/pradtice/android/build.gradle @@ -0,0 +1,22 @@ +allprojects { + repositories { + google() + mavenCentral() + // Tmap의 repository 추가 +// maven { +// url = "https://devrepo.tmapadmin.com/repository/tmap-sdk-release/" +// } + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/frontend/pradtice/android/gradle.properties b/frontend/pradtice/android/gradle.properties new file mode 100644 index 0000000000..598d13fee4 --- /dev/null +++ b/frontend/pradtice/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx4G +android.useAndroidX=true +android.enableJetifier=true diff --git a/frontend/pradtice/android/gradle/wrapper/gradle-wrapper.properties b/frontend/pradtice/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..e1ca574ef0 --- /dev/null +++ b/frontend/pradtice/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip diff --git a/frontend/pradtice/android/settings.gradle b/frontend/pradtice/android/settings.gradle new file mode 100644 index 0000000000..1d6d19b7f8 --- /dev/null +++ b/frontend/pradtice/android/settings.gradle @@ -0,0 +1,26 @@ +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + } + settings.ext.flutterSdkPath = flutterSdkPath() + + includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "7.3.0" apply false + id "org.jetbrains.kotlin.android" version "1.7.10" apply false +} + +include ":app" diff --git a/frontend/pradtice/assets/eye_u.png b/frontend/pradtice/assets/eye_u.png new file mode 100644 index 0000000000..256bf58a57 Binary files /dev/null and b/frontend/pradtice/assets/eye_u.png differ diff --git a/frontend/pradtice/assets/eye_u_mono.png b/frontend/pradtice/assets/eye_u_mono.png new file mode 100644 index 0000000000..7739429e8a Binary files /dev/null and b/frontend/pradtice/assets/eye_u_mono.png differ diff --git a/frontend/pradtice/assets/labels.txt b/frontend/pradtice/assets/labels.txt new file mode 100644 index 0000000000..1f42c8eb44 --- /dev/null +++ b/frontend/pradtice/assets/labels.txt @@ -0,0 +1,80 @@ +person +bicycle +car +motorcycle +airplane +bus +train +truck +boat +traffic light +fire hydrant +stop sign +parking meter +bench +bird +cat +dog +horse +sheep +cow +elephant +bear +zebra +giraffe +backpack +umbrella +handbag +tie +suitcase +frisbee +skis +snowboard +sports ball +kite +baseball bat +baseball glove +skateboard +surfboard +tennis racket +bottle +wine glass +cup +fork +knife +spoon +bowl +banana +apple +sandwich +orange +broccoli +carrot +hot dog +pizza +donut +cake +chair +couch +potted plant +bed +dining table +toilet +tv +laptop +mouse +remote +keyboard +cell phone +microwave +oven +toaster +sink +refrigerator +book +clock +vase +scissors +teddy bear +hair drier +toothbrush \ No newline at end of file diff --git a/frontend/pradtice/assets/tessdata/spa.traineddata b/frontend/pradtice/assets/tessdata/spa.traineddata new file mode 100644 index 0000000000..f703e0535e Binary files /dev/null and b/frontend/pradtice/assets/tessdata/spa.traineddata differ diff --git a/frontend/pradtice/assets/tessdata_config.json b/frontend/pradtice/assets/tessdata_config.json new file mode 100644 index 0000000000..521c2d9ba1 --- /dev/null +++ b/frontend/pradtice/assets/tessdata_config.json @@ -0,0 +1,5 @@ +{ + "files": [ + "spa.traineddata" + ] + } \ No newline at end of file diff --git a/frontend/pradtice/assets/yolov5n.tflite b/frontend/pradtice/assets/yolov5n.tflite new file mode 100644 index 0000000000..0ccf9e4f18 Binary files /dev/null and b/frontend/pradtice/assets/yolov5n.tflite differ diff --git a/frontend/pradtice/assets/yolov8n-seg.tflite b/frontend/pradtice/assets/yolov8n-seg.tflite new file mode 100644 index 0000000000..9f089da3f6 Binary files /dev/null and b/frontend/pradtice/assets/yolov8n-seg.tflite differ diff --git a/frontend/pradtice/assets/yolov8n.tflite b/frontend/pradtice/assets/yolov8n.tflite new file mode 100644 index 0000000000..b8aeb41b16 Binary files /dev/null and b/frontend/pradtice/assets/yolov8n.tflite differ diff --git a/frontend/pradtice/ios/.gitignore b/frontend/pradtice/ios/.gitignore new file mode 100644 index 0000000000..7a7f9873ad --- /dev/null +++ b/frontend/pradtice/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/frontend/pradtice/ios/Flutter/AppFrameworkInfo.plist b/frontend/pradtice/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000000..7c56964006 --- /dev/null +++ b/frontend/pradtice/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 + + diff --git a/frontend/pradtice/ios/Flutter/Debug.xcconfig b/frontend/pradtice/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000000..ec97fc6f30 --- /dev/null +++ b/frontend/pradtice/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/frontend/pradtice/ios/Flutter/Release.xcconfig b/frontend/pradtice/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000000..c4855bfe20 --- /dev/null +++ b/frontend/pradtice/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/frontend/pradtice/ios/Podfile b/frontend/pradtice/ios/Podfile new file mode 100644 index 0000000000..d97f17e223 --- /dev/null +++ b/frontend/pradtice/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '12.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/frontend/pradtice/ios/Runner.xcodeproj/project.pbxproj b/frontend/pradtice/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..aa9eb53348 --- /dev/null +++ b/frontend/pradtice/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,619 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 9U2RH48PC7; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 9U2RH48PC7; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 9U2RH48PC7; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..919434a625 --- /dev/null +++ b/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000..f9b0d7c5ea --- /dev/null +++ b/frontend/pradtice/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/frontend/pradtice/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/frontend/pradtice/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000000..8e3ca5dfe1 --- /dev/null +++ b/frontend/pradtice/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/pradtice/ios/Runner.xcworkspace/contents.xcworkspacedata b/frontend/pradtice/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..1d526a16ed --- /dev/null +++ b/frontend/pradtice/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/frontend/pradtice/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/pradtice/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/frontend/pradtice/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/frontend/pradtice/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/frontend/pradtice/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000..f9b0d7c5ea --- /dev/null +++ b/frontend/pradtice/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/frontend/pradtice/ios/Runner/AppDelegate.swift b/frontend/pradtice/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000000..70693e4a8c --- /dev/null +++ b/frontend/pradtice/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..d36b1fab2d --- /dev/null +++ b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000..dc9ada4725 Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000000..7353c41ecf Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000000..797d452e45 Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000..6ed2d933e1 Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000000..4cd7b0099c Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000..fe730945a0 Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000000..321773cd85 Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000000..797d452e45 Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000..502f463a9b Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000..0ec3034392 Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000..0ec3034392 Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000..e9f5fea27c Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000..84ac32ae7d Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000000..8953cba090 Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000000..0467bf12aa Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000000..0bedcf2fd4 --- /dev/null +++ b/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000000..9da19eacad Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000..9da19eacad Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000..9da19eacad Binary files /dev/null and b/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000000..89c2725b70 --- /dev/null +++ b/frontend/pradtice/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +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. \ No newline at end of file diff --git a/frontend/pradtice/ios/Runner/Base.lproj/LaunchScreen.storyboard b/frontend/pradtice/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000000..f2e259c7c9 --- /dev/null +++ b/frontend/pradtice/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/pradtice/ios/Runner/Base.lproj/Main.storyboard b/frontend/pradtice/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000000..f3c28516fb --- /dev/null +++ b/frontend/pradtice/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/pradtice/ios/Runner/Info.plist b/frontend/pradtice/ios/Runner/Info.plist new file mode 100644 index 0000000000..8976076fc6 --- /dev/null +++ b/frontend/pradtice/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Pradtice + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + pradtice + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/frontend/pradtice/ios/Runner/Runner-Bridging-Header.h b/frontend/pradtice/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000000..308a2a560b --- /dev/null +++ b/frontend/pradtice/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/frontend/pradtice/ios/RunnerTests/RunnerTests.swift b/frontend/pradtice/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000000..86a7c3b1b6 --- /dev/null +++ b/frontend/pradtice/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/frontend/pradtice/lib/GetAndroidID.dart b/frontend/pradtice/lib/GetAndroidID.dart new file mode 100644 index 0000000000..71faaf5c86 --- /dev/null +++ b/frontend/pradtice/lib/GetAndroidID.dart @@ -0,0 +1,45 @@ +import 'package:android_id/android_id.dart'; +import 'package:flutter/services.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; + + +class GetID { + static const _androidIdPlugin = AndroidId(); + String id = ''; + + GetID() { + setID().then((_) { + // GET 방식으로 서버에 전송 + SendToServer(); + print(id); + }); + } + + Future setID() async { + String AndroidID; + try { + AndroidID = await _androidIdPlugin.getId() ?? 'Unknown ID'; + } on PlatformException { + AndroidID = 'Failed to get Android ID.'; + } + id = AndroidID; + } + + Future SendToServer() async { + // URL에 파라미터를 포함하여 GET 요청을 보냅니다. + var url = Uri.parse('http://15.164.219.111:8080/checkMember?uuid=$id'); + + try { + var response = await http.get(url); + if (response.statusCode != 200) { + print("서버에 전송 실패"); + } else { + print("서버에 전송 완료"); + print(jsonDecode(response.body)); + } + } catch (e) { + print("에러 코드 : $e"); + } + } +} diff --git a/frontend/pradtice/lib/GoogleMap.dart b/frontend/pradtice/lib/GoogleMap.dart new file mode 100644 index 0000000000..33e3d6070e --- /dev/null +++ b/frontend/pradtice/lib/GoogleMap.dart @@ -0,0 +1,102 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'location_permission.dart'; +//수정 본 +class MyGoogleMap extends StatelessWidget { + @override + Widget build(BuildContext context) { + return _MapSample(); + } +} + +class _MapSample extends StatefulWidget { + @override + State<_MapSample> createState() => _MapSampleState(); +} + +class _MapSampleState extends State<_MapSample> { + Completer _controller = Completer(); + + Set _markers = {}; + MyLocation myLocation = MyLocation(); + + static final CameraPosition _kGooglePlex = CameraPosition( + target: LatLng(37.5271883, 126.9659283), + zoom: 14.4746, + ); + + static final CameraPosition _kLake = CameraPosition( + bearing: 192.8334901395799, + target: LatLng(37.43296265331129, -122.08832357078792), + tilt: 59.440717697143555, + zoom: 19.151926040649414); + + // 남산타워 위치 설정 + static final CameraPosition _kNamsanTower = CameraPosition( + target: LatLng(37.5511694, 126.9882266), + zoom: 14.4746, + ); + + @override + void initState() { + super.initState(); + _initializeMarkers(); + } + + void _initializeMarkers() { + _markers.add( + Marker( + markerId: MarkerId('_kGooglePlex'), + position: _kGooglePlex.target, + infoWindow: InfoWindow( + title: 'Google Plex', + snippet: 'Google Headquarters', + ), + icon: BitmapDescriptor.defaultMarker, + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: GoogleMap( + mapType: MapType.hybrid, + initialCameraPosition: _kGooglePlex, + markers: _markers, + onMapCreated: (GoogleMapController controller) { + _controller.complete(controller); + }, + ), + floatingActionButton: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + FloatingActionButton.extended( + onPressed: (){myLocation.getMyCurrentLocation();}, + label: Text('To the lake!'), + icon: Icon(Icons.directions_boat), + ), + SizedBox(width: 16), // 버튼 사이의 간격 + FloatingActionButton.extended( + onPressed: _goToNamsanTower, + label: Text('To Namsan Tower!'), + icon: Icon(Icons.landscape), + ), + ], + ), + ); + } + + Future _goToTheLake() async { + final GoogleMapController controller = await _controller.future; + controller.animateCamera(CameraUpdate.newCameraPosition(_kLake)); + } + + // 남산타워로 이동하는 함수 + Future _goToNamsanTower() async { + final GoogleMapController controller = await _controller.future; + controller.animateCamera(CameraUpdate.newCameraPosition(_kNamsanTower)); + } +} + diff --git a/frontend/pradtice/lib/ObjectRecognitionMode.dart b/frontend/pradtice/lib/ObjectRecognitionMode.dart new file mode 100644 index 0000000000..301431a78f --- /dev/null +++ b/frontend/pradtice/lib/ObjectRecognitionMode.dart @@ -0,0 +1,385 @@ +import 'dart:io'; +import 'dart:typed_data'; +import 'dart:ui'; + +import 'package:camera/camera.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_speed_dial/flutter_speed_dial.dart'; +import 'dart:async'; +import 'package:flutter_vision/flutter_vision.dart'; +import 'package:image_picker/image_picker.dart'; +import 'TextToSpeech.dart'; +import 'package:vibration/vibration.dart'; + +import 'sever.dart'; +enum Options { none, imagev5, imagev8, imagev8seg, frame } + +late List cameras; + +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + DartPluginRegistrant.ensureInitialized(); + runApp( + const MaterialApp( + home: ObjectReco(tabnum: 1,), + ), + ); +} + + +class ObjectReco extends StatefulWidget { + const ObjectReco({Key? key,required this.tabnum}) : super(key: key); + final int tabnum; + + @override + State createState() => _ObjectRecoState(); +} + +class _ObjectRecoState extends State { + late FlutterVision vision; + Options option = Options.frame; + + @override + void initState() { + super.initState(); + vision = FlutterVision(); + } + + @override + void dispose() async { + super.dispose(); + await vision.closeTesseractModel(); + await vision.closeYoloModel(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: task(option), + ); + } + + Widget task(Options option) { + if (option == Options.frame) { + return YoloVideo(vision: vision,tabnum: widget.tabnum,); + } + return const Center(child: Text("Choose Task")); + } +} + +class YoloVideo extends StatefulWidget { + final FlutterVision vision; + final int tabnum; + const YoloVideo({Key? key, required this.vision, required this.tabnum}) : super(key: key); + + @override + State createState() => _YoloVideoState(); +} + +class _YoloVideoState extends State { + late CameraController controller; + late List> yoloResults; + CameraImage? cameraImage; + bool isLoaded = false; + bool isDetecting = false; + TTS tts = TTS(message: ''); + Sever sever = Sever(); + + Timer? timer; + + @override + void initState() { + super.initState(); + init(); + } + + // 카메라 초기화 + void init() async { + cameras = await availableCameras(); + controller = CameraController(cameras[0], ResolutionPreset.medium); + await controller.initialize(); + await loadYoloModel(); + sever.setid(); + setState(() { + isLoaded = true; + isDetecting = false; + yoloResults = []; + }); + } + + @override + void dispose() async { + super.dispose(); + timer?.cancel(); + controller.dispose(); + } + + @override + Widget build(BuildContext context) { + final Size size = MediaQuery.of(context).size; + if (!isLoaded) { + return const Scaffold( + body: Center( + child: Text("Model not loaded, waiting for it"), + ), + ); + } + if(widget.tabnum==1){ + return GestureDetector( + onTap: () { + startDetection(); + sever.current_location(); + }, + onDoubleTap: () { + sever.ttsread(); + }, + onLongPress: () { + tts.setMessage('경로안내를 취소하려면 한번, 아니면 두번을 터치하세요'); + tts.speak(); + showDialog( + context: context, + builder: (context) => GestureDetector( + onTap: () { + Navigator.pop(context); + Navigator.pop(context); + timer?.cancel(); + sever.cancel_navi(); + }, + onDoubleTap: () { + Navigator.pop(context); + }, + )); + }, + child: Stack( + fit: StackFit.expand, + children: [ + AspectRatio( + aspectRatio: controller.value.aspectRatio, + child: CameraPreview(controller), + ), + ...displayBoxesAroundRecognizedObjects(size), + + //탐지 확인용 아이콘 + // Positioned( + // bottom: 75, + // width: MediaQuery.of(context).size.width, + // child: Center( + // child: Icon( + // isDetecting ? Icons.stop : Icons.play_arrow, + // color: isDetecting ? Colors.red : Colors.white, // Adjust icon color + // size: 80, // Adjust icon size + // ), + // ), + // ), + ], + ), + ); + } else{ + return GestureDetector( + onTap: () { + if (!isDetecting) { + startDetection(); + } else { + // Execute stopDetection when isDetecting is true + stopDetection(); + } + }, + child: Stack( + fit: StackFit.expand, + children: [ + AspectRatio( + aspectRatio: controller.value.aspectRatio, + child: CameraPreview(controller), + ), + ...displayBoxesAroundRecognizedObjects(size), + + //탐지 확인용 아이콘 + // Positioned( + // bottom: 75, + // width: MediaQuery.of(context).size.width, + // child: Center( + // child: Icon( + // isDetecting ? Icons.stop : Icons.play_arrow, + // color: isDetecting ? Colors.red : Colors.white, // Adjust icon color + // size: 80, // Adjust icon size + // ), + // ), + // ), + ], + ), + ); + } + } + + // YOLO 모델 로드 + Future loadYoloModel() async { + await widget.vision.loadYoloModel( + labels: 'assets/labels.txt', + modelPath: 'assets/yolov5n.tflite', + modelVersion: "yolov5", + numThreads: 2, + useGpu: true, + ); + } + + // 객체 탐지 시작 + Future startDetection() async { + setState(() { + isDetecting = true; + }); + if (!controller.value.isStreamingImages) { + await controller.startImageStream((image) { + if (isDetecting) { + cameraImage = image; + yoloOnFrame(image); + } + }); + } + } + + // 객체 탐지 중지 + Future stopDetection() async { + setState(() { + isDetecting = false; + yoloResults.clear(); + }); + } + + // 카메라 프레임에서 YOLO 객체 탐지 + Future yoloOnFrame(CameraImage cameraImage) async { + final result = await widget.vision.yoloOnFrame( + bytesList: cameraImage.planes.map((plane) => plane.bytes).toList(), + imageHeight: cameraImage.height, + imageWidth: cameraImage.width, + iouThreshold: 0.4, + confThreshold: 0.4, + classThreshold: 0.5, + ); + + if (result.isNotEmpty) { + setState(() { + // 필터링할 클래스 레이블 + List targetLabels = [ + "bicycle", + "car", + "motorbike", + "traffic light", + "fire hydrant", + "stop sign", + "parking meter", + "person", + "chair", + ]; + + // 필터링된 결과를 저장할 리스트 + List> filteredResults = []; + + // 필터링된 결과를 추출 + for (var obj in result) { + if (targetLabels.contains(obj['tag'])) { + filteredResults.add(obj); + } + } + + // 필터링된 결과를 사용하여 작업 수행 + for (var obj in filteredResults) { + double bottomY = obj['box'][1] + obj['box'][3]; + if (bottomY > 730 && targetLabels.contains(obj['tag'])) { + // tts.setMessage('위험'); + // tts.speak(); + Vibration.vibrate(duration: 500); + } + } + + // 필터링된 결과를 yoloResults에 업데이트 + yoloResults = filteredResults; + }); + } + } + + // 객체를 인식하여 박스 표시 + List displayBoxesAroundRecognizedObjects(Size screen) { + if (yoloResults.isEmpty) return []; + + double factorX = screen.width / (cameraImage?.height ?? 1); + double factorY = screen.height / (cameraImage?.width ?? 1); + + // 필터링할 클래스 레이블 + List targetLabels = [ + "bicycle", + "car", + "motorbike", + "traffic light", + "fire hydrant", + "stop sign", + "parking meter", + "person", + "chair" + ]; + + // 필터링된 결과를 저장할 리스트 + List> filteredResults = []; + + // 필터링된 결과를 추출 + for (var result in yoloResults) { + if (targetLabels.contains(result['tag'])) { + filteredResults.add(result); + } + } + + Color colorPick = const Color.fromARGB(255, 50, 233, 30); + + return filteredResults.map((result) { + return Positioned( + left: result["box"][0] * factorX, + top: result["box"][1] * factorY, + width: (result["box"][2] - result["box"][0]) * factorX, + height: (result["box"][3] - result["box"][1]) * factorY, + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(10.0)), + border: Border.all(color: Colors.pink, width: 2.0), + ), + child: Text( + "${result['tag']} ${(result['box'][4] * 100).toStringAsFixed(0)}%", + style: TextStyle( + background: Paint()..color = colorPick, + color: Colors.white, + fontSize: 18.0, + ), + ), + ), + ); + }).toList(); + } +} + +class PolygonPainter extends CustomPainter { + final List> points; + + PolygonPainter({required this.points}); + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..color = const Color.fromARGB(129, 255, 2, 124) + ..strokeWidth = 2 + ..style = PaintingStyle.fill; + + final path = Path(); + if (points.isNotEmpty) { + path.moveTo(points[0]['x']!, points[0]['y']!); + for (var i = 1; i < points.length; i++) { + path.lineTo(points[i]['x']!, points[i]['y']!); + } + path.close(); + } + + canvas.drawPath(path, paint); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return false; + } +} diff --git a/frontend/pradtice/lib/STT.dart b/frontend/pradtice/lib/STT.dart new file mode 100644 index 0000000000..3b3654d72e --- /dev/null +++ b/frontend/pradtice/lib/STT.dart @@ -0,0 +1,224 @@ +import 'package:flutter/material.dart'; +import 'ObjectRecognitionMode.dart'; +import 'sever.dart'; // 서버 연동 파일 import +import 'dart:async'; //탭 시간차 패키지 +import 'package:speech_to_text/speech_recognition_result.dart'; // 음성 인식 패키지 +import 'package:speech_to_text/speech_to_text.dart'; // stt -> tts 패키지 + +// import 'Tmap.dart'; +import 'GoogleMap.dart'; +import 'TextToSpeech.dart'; + +class SttTab extends StatefulWidget { + const SttTab({Key? key}) : super(key: key); + + @override + State createState() => _SttTabState(); +} + +class _SttTabState extends State { + SpeechToText _speechToText = SpeechToText(); + bool speechEnable = false; + String _lastWords = '음성인식'; + Sever sever = Sever(); + bool _isListening = false; + TTS tts = TTS(message: '화면을 누르면서 기능을 말씀해주세요.'); + + @override + void initState() { + super.initState(); + _initSpeech(); + tts.speak(); + } + + void _initSpeech() async { + speechEnable = await _speechToText.initialize(); + setState(() {}); + } + + void _startListening() async { + await _speechToText.listen(onResult: _onSpeechResult); + setState(() { + _isListening = true; + }); + } + + void _stopListening() async { + await _speechToText.stop(); + setState(() { + _isListening = false; + }); + tts.setMessage(' $_lastWords 가 맞으면 한번, 틀리면 두번 터치를 해주세요.'); + tts.speak(); + showDialog(context: context, + builder: (context) => GestureDetector( + onTap: (){ + Navigator.pop(context); + Navigator.pop(context); + if(_lastWords=='보행 모드'){ + Navigator.push(context, MaterialPageRoute(builder: (context) => ObjectReco(tabnum: 0)),); + } + else if (_lastWords == '경로 탐색 모드') { + Navigator.push(context, MaterialPageRoute(builder: (context) => SttAdress())); + } else if (_lastWords == '테스트 모드'){ + Navigator.push(context, MaterialPageRoute(builder: (context) => NaviTap())); + } + }, + onDoubleTap: (){ + Navigator.pop(context); + Navigator.pop(context); + Navigator.push(context, MaterialPageRoute(builder: (context) => SttTab())); + }, + )); + } + + void _onSpeechResult(SpeechRecognitionResult result) { + setState(() { + _lastWords = result.recognizedWords; + }); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTapDown: (_) => _startListening(), + onTapUp: (_) => _stopListening(), + child: Dialog( + child: Scaffold( + appBar: AppBar(title: Text('음성인식')), + body: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: Center( + child: Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('화면을 누르면서 음성인식 시작',style: TextStyle(fontSize: 20),), + Container(height: 10,), + Text(_lastWords,style: TextStyle(fontSize: 25),), + Container(height: 50,), + Icon( + _isListening ? Icons.mic : Icons.mic_off, + size: 50, + ), + ], + ), + ), + ), + ), + ], + ), + ), + ), + ); + } + + + +} + +class SttAdress extends StatefulWidget { + const SttAdress({super.key}); + + @override + State createState() => _SttAdressState(); +} + +class _SttAdressState extends State { + SpeechToText _speechToText = SpeechToText(); + bool speechEnable = false; + String _lastWords = ''; + Sever sever = Sever(); + bool _isListening = false; + TTS tts = TTS(message: ' 화면을 누르면서 목적지를 말씀해주세요.'); + + @override + void initState() { + super.initState(); + _initSpeech(); + tts.speak(); + } + + void _initSpeech() async { + speechEnable = await _speechToText.initialize(); + setState(() {}); + } + + void _startListening() async { + await _speechToText.listen(onResult: _onSpeechResult); + setState(() { + _isListening = true; + }); + } + + void _stopListening() async { + await _speechToText.stop(); + setState(() { + _isListening = false; + }); + tts.setMessage(' $_lastWords 가 맞으면 한번, 틀리면 두번 터치를 해주세요.'); + tts.speak(); + showDialog(context: context, + builder: (context) => GestureDetector( + onTap: (){ + sever.setAdress(_lastWords); + Navigator.pop(context); + Navigator.pop(context); + //sever.start_navi(); + //Navigator.push(context, MaterialPageRoute(builder: (context) => ObjectReco(tabnum: 1,))); + }, + onDoubleTap: (){ + Navigator.pop(context); + Navigator.pop(context); + Navigator.push(context, MaterialPageRoute(builder: (context) => SttAdress())); + }, + )); + } + + void _onSpeechResult(SpeechRecognitionResult result) { + setState(() { + _lastWords = result.recognizedWords; + }); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTapDown: (_) => _startListening(), + onTapUp: (_) => _stopListening(), + child: Dialog( + child: Scaffold( + appBar: AppBar(title: Text('음성인식')), + body: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: Center( + child: Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('화면을 누르면서 음성인식 시작',style: TextStyle(fontSize: 20),), + Container(height: 10,), + Text(_lastWords,style: TextStyle(fontSize: 25),), + Container(height: 50,), + Icon( + _isListening ? Icons.mic : Icons.mic_off, + size: 50, + ), + ], + ), + ), + ), + ), + ], + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/frontend/pradtice/lib/TextToSpeech.dart b/frontend/pradtice/lib/TextToSpeech.dart new file mode 100644 index 0000000000..99b5ee6b18 --- /dev/null +++ b/frontend/pradtice/lib/TextToSpeech.dart @@ -0,0 +1,24 @@ +import 'package:flutter_tts/flutter_tts.dart'; +import 'package:flutter/material.dart'; + +class TTS{ + String message; + final FlutterTts tts = FlutterTts(); + + TTS({required this.message}){ + initialize(); + } + + void initialize() async { + await tts.setLanguage('ko-KR'); + await tts.setSpeechRate(0.5); + } + + void setMessage(String setMessage){ + message = setMessage; + } + + void speak(){ + tts.speak(message); + } +} \ No newline at end of file diff --git a/frontend/pradtice/lib/Tmap.dart b/frontend/pradtice/lib/Tmap.dart new file mode 100644 index 0000000000..f423932ae5 --- /dev/null +++ b/frontend/pradtice/lib/Tmap.dart @@ -0,0 +1,98 @@ + +// import 'package:flutter/material.dart'; +// import 'package:provider/provider.dart'; +// import 'package:tmap_ui_sdk/tmap_ui_sdk.dart'; +// +// // Tmap SDK 인증 및 초기화 +// Future initTmap() async { +// try { +// // 사용자 단말의 플랫폼 버전을 획득 +// String? platformVersion = await TmapUiSdk().getPlatformVersion(); +// +// // 사용자 인증 입력 +// AuthData authData = AuthData( +// clientApiKey: "4m4ftbOA1eahz7OJQgmfDAi7P7ugSO89PeiYSEA7", // 필수 +// userKey: "", +// clientServiceName: "", +// clientID: "", +// clientDeviceId: "", +// clientAppVersion: "", +// clientApCode: "", +// ); +// +// // 사용자 인증, 초기화 +// InitResult? result = await TmapUISDKManager().initSDK(authData); +// +// if (platformVersion != null && result != null && result == InitResult.granted) { +// print("초기화 성공 : $platformVersion / $result"); +// } else { +// print("초기화 실패 : $platformVersion / $result"); +// } +// } catch (e) { +// print("error ${e.toString()}"); +// } +// } +// +// // 사용자의 차량 정보와 SDK UI의 속성을 설정하는 클래스 +// class ConfigCarModel { +// SDKConfig get normalCar => SDKConfig( +// carType: UISDKCarModel.normal, +// fuelType: UISDKFuel.gas, +// showTrafficAccident: true, +// mapTextSize: UISDKMapFontSize.small, +// nightMode: UISDKAutoNightModeType.auto, +// isUseSpeedReactMapScale: true, +// isShowTrafficInRoute: false, +// isShowExitPopupWhenStopDriving: true, +// ); +// } +// +// // 프로젝트 전역에서 사용할 Home 위젯 +// class Home extends StatelessWidget { +// const Home({Key? key}) : super(key: key); +// +// @override +// Widget build(BuildContext context) { +// return MultiProvider( +// providers: [ +// Provider(create: (context) => ConfigCarModel()), +// ], +// child: MaterialApp.router( +// title: "NAVI SDK SAMPLE", +// theme: ThemeData(primarySwatch: Colors.blue), +// debugShowCheckedModeBanner: false, +// routerConfig: _router, +// ), +// ); +// } +// } +// +// // 차량 설정 적용 +// Future setCarConfig(BuildContext context) async { +// ConfigCarModel model = context.read(); +// +// bool? result = await TmapUISDKManager().setConfigSDK(model.normalCar); +// +// return result; +// } +// +// // 경로 요청 위젯 +// TmapViewWidget getTmapViewWidget() { +// RouteRequestData data = RouteRequestData( +// source: null, // 출발지, null 일 때 SDK 내부적으로 현재위치에서 시작 +// destination: RoutePoint( +// latitude: 37.566491, +// longitude: 126.985146, +// name: "SKT Tower", +// ), // 목적지, 필수 +// routeOption: [ +// PlanningOption.recommend, +// PlanningOption.shortest, +// ], // 경로 옵션 +// wayPoints: null, // 경유지 +// safeDriving: false, // 안전 운행 +// guideWithoutPreview: false, // 선택 없이 바로 안내 +// ); +// +// return TmapViewWidget(data: data); +// } diff --git a/frontend/pradtice/lib/camera/box_widget.dart b/frontend/pradtice/lib/camera/box_widget.dart new file mode 100644 index 0000000000..d8d5a85a37 --- /dev/null +++ b/frontend/pradtice/lib/camera/box_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:pradtice/camera/recognition.dart'; + +class BoxWidget extends StatelessWidget { + final Recognition result; + // BoxWidget 생성자 + const BoxWidget({Key? key, required this.result}) : super(key: key); + @override + Widget build(BuildContext context) { + // 결과에 따라 색상을 설정 + Color color = Colors.primaries[((result.label?.length ?? 0) + + result.label!.codeUnitAt(0) + + (result.id ?? 0)) % + Colors.primaries.length]; + // Positioned 위젯을 사용하여 인식된 객체의 위치와 크기를 설정 + return Positioned( + left: result.renderLocation.left, + top: result.renderLocation.top, + width: result.renderLocation.width, + height: result.renderLocation.height, + child: Container( + width: result.renderLocation.width, + height: result.renderLocation.height, + // 경계 상자의 테두리 + decoration: BoxDecoration( + border: Border.all(color: color, width: 3), + ), + child: Align( + alignment: Alignment.topLeft, + child: FittedBox( + // 인식된 객체의 레이블과 확률 표시 + child: Container( + color: color, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text('${result.label} ${result.score!.toStringAsFixed(2)}'), + ], + ), + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/frontend/pradtice/lib/camera/camera_settings.dart b/frontend/pradtice/lib/camera/camera_settings.dart new file mode 100644 index 0000000000..437325bb37 --- /dev/null +++ b/frontend/pradtice/lib/camera/camera_settings.dart @@ -0,0 +1,17 @@ +import 'dart:ui'; + +class CameraSettings { + // 카메라 프리뷰의 가로 세로 비율을 저장하는 변수 + static double? ratio; + // 화면 크기를 저장하는 변수 + static Size? screenSize; + // 입력 이미지 크기를 저장하는 변수 + static Size? inputImageSize; + // 실제 프리뷰 크기를 계산하여 반환하는 getter + static Size get actualPreviewSize => Size( + // 화면의 너비 + screenSize?.width ?? 0, + // 화면의 너비에 비율을 곱하여 높이를 계산 + (screenSize?.width ?? 0) * (ratio ?? 0), + ); +} \ No newline at end of file diff --git a/frontend/pradtice/lib/camera/camera_view.dart b/frontend/pradtice/lib/camera/camera_view.dart new file mode 100644 index 0000000000..b9ce29e44d --- /dev/null +++ b/frontend/pradtice/lib/camera/camera_view.dart @@ -0,0 +1,143 @@ +import 'dart:isolate'; +import 'package:camera/camera.dart'; +import 'package:flutter/material.dart'; +import 'package:pradtice/camera/classifier.dart'; +import 'package:pradtice/camera/recognition.dart'; +import 'package:pradtice/camera/camera_settings.dart'; +import 'package:pradtice/camera/isolate_utils.dart'; + +//각 프레임을 추론에 전달하는 CameraView +class CameraView extends StatefulWidget { + // 결과를 반환하기 위한 콜백 함수 + final Function(List recognitions) resultsCallback; + // 추론 시간을 업데이트하기 위한 콜백 함수 + final Function(int elapsedTime) updateElapsedTimeCallback; + // CameraView 생성자 + const CameraView(this.resultsCallback, this.updateElapsedTimeCallback); + @override + _CameraViewState createState() => _CameraViewState(); +} +class _CameraViewState extends State with WidgetsBindingObserver { + // 사용 가능한 카메라 목록 + List? cameras; + // 카메라 컨트롤러 + CameraController? cameraController; + // 추론 중일 때 true + bool? predicting; + // Classifier 인스턴스 + Classifier? classifier; + // IsolateUtils 인스턴스 + IsolateUtils? isolateUtils; + @override + void initState() { + super.initState(); + initStateAsync(); + } + void initStateAsync() async { + WidgetsBinding.instance.addObserver(this); + // 새로운 Isolate를 생성 + isolateUtils = IsolateUtils(); + await isolateUtils?.start(); + // 카메라 초기화 + initializeCamera(); + // 모델 및 레이블을 로드하기 위해 Classifier 인스턴스 생성 + classifier = Classifier(); + // 초기에 predicting은 false로 설정 + predicting = false; + } + // 카메라를 초기화하고 cameraController를 설정 + void initializeCamera() async { + cameras = await availableCameras(); + // cameras[0]은 후면 카메라 + cameraController = + CameraController(cameras![0], ResolutionPreset.low, enableAudio: false); + cameraController?.initialize().then((_) async { + // onLatestImageAvailable 함수를 전달하여 각 프레임에 대한 인식을 수행 + await cameraController?.startImageStream(onLatestImageAvailable); + // 현재 카메라의 미리보기의 크기 + Size? previewSize = cameraController?.value.previewSize; + CameraSettings.inputImageSize = previewSize; + // 해당 스마트폰의 화면의 크기 + Size screenSize = MediaQuery.of(context).size; + CameraSettings.screenSize = screenSize; + //프리뷰 프레임의 너비와 화면 너비 간의 비율 + CameraSettings.ratio = screenSize.width / (previewSize?.height ?? 0); + }); + } + @override + Widget build(BuildContext context) { + // 카메라가 초기화되지 않은 경우 빈 컨테이너 반환 + if (cameraController == null || !cameraController!.value.isInitialized) { + return Container(); + } + // 카메라 프리뷰 + return AspectRatio( + //카메라 프리뷰 화면의 가로 세로 비율 + aspectRatio: 1 / cameraController!.value.aspectRatio, + child: CameraPreview(cameraController!), + ); + } + // 프레임마다 호출 + onLatestImageAvailable(CameraImage cameraImage) async { + if (classifier?.interpreter != null && classifier?.labels != null) { + // 이전 추론이 완료되지 않은 경우 반환 + if (predicting ?? false) { + return; + } + setState(() { + // 이전 추론 완료 + predicting = true; + }); + //추론 시작 시간 + var uiThreadTimeStart = DateTime.now().millisecondsSinceEpoch; + // 추론 Isolate에 전달할 데이터 + var isolateData = IsolateData(cameraImage, + classifier?.interpreter?.address ?? 0, classifier?.labels ?? []); + // 추론 결과 반환 + Map inferenceResults = await inference(isolateData); + // 추론 시간 계산 + var uiThreadInferenceElapsedTime = + DateTime.now().millisecondsSinceEpoch - uiThreadTimeStart; + // 결과를 HomeView로 전달 + widget.resultsCallback(inferenceResults["recognitions"]); + // 추론 시간 HomeView로 전달 + widget.updateElapsedTimeCallback(uiThreadInferenceElapsedTime); + // 새로운 프레임을 허용하기 위해 predicting을 false로 설정 + setState(() { + predicting = false; + }); + } + } + // 다른 Isolate에서 추론을 실행 + Future> inference(IsolateData isolateData) async { + ReceivePort responsePort = ReceivePort(); + isolateUtils?.sendPort + ?.send(isolateData..responsePort = responsePort.sendPort); + var results = await responsePort.first; + return results; + } + @override + // 앱이 일시 중지되거나 재개될 때 호출 + void didChangeAppLifecycleState(AppLifecycleState state) async { + switch (state) { + // 앱이 일시 중지되면 카메라 컨트롤러의 이미지 스트림 중지 + case AppLifecycleState.paused: + cameraController?.stopImageStream(); + break; + // 앱이 재개되면 카메라 컨트롤러의 이미지 스트림을 다시 시작 + case AppLifecycleState.resumed: + if (!cameraController!.value.isStreamingImages) { + await cameraController?.startImageStream(onLatestImageAvailable); + } + break; + default: + } + } + @override + // 앱이 화면에서 사라질 때 호출 + void dispose() { + WidgetsBinding.instance.removeObserver(this); + cameraController?.dispose(); + super.dispose(); + } +} \ No newline at end of file diff --git a/frontend/pradtice/lib/camera/classifier.dart b/frontend/pradtice/lib/camera/classifier.dart new file mode 100644 index 0000000000..7475f44935 --- /dev/null +++ b/frontend/pradtice/lib/camera/classifier.dart @@ -0,0 +1,133 @@ +import 'dart:math'; +import 'dart:ui'; +import 'package:flutter/material.dart'; +import 'package:image/image.dart' as imageLib; +import 'package:pradtice/camera/recognition.dart'; +import 'package:tflite_flutter/tflite_flutter.dart'; +import 'package:tflite_flutter_helper/tflite_flutter_helper.dart'; + +class Classifier { + // 인터프리터 및 레이블 저장 + Interpreter? _interpreter; + List? _labels; + // 모델 및 레이블 파일 이름, 입력 크기, 임계값 정의 + static const String MODEL_FILE_NAME = "detect.tflite"; + static const String LABEL_FILE_NAME = "labelmap.txt"; + static const int INPUT_SIZE = 300; + static const double THRESHOLD = 0.5; + ImageProcessor? imageProcessor; + int? padSize; + List>? _outputShapes; + List? _outputTypes; + static const int NUM_RESULTS = 10; + // Classifier 클래스 생성자 + Classifier({ + Interpreter? interpreter, + List? labels, + }) { + loadModel(interpreter: interpreter); + loadLabels(labels: labels); + } + // 머신러닝 모델 로드 + void loadModel({Interpreter? interpreter}) async { + try { + _interpreter = interpreter ?? + await Interpreter.fromAsset( + MODEL_FILE_NAME, + options: InterpreterOptions()..threads = 4, + ); + var outputTensors = _interpreter?.getOutputTensors(); + _outputShapes = []; + _outputTypes = []; + outputTensors?.forEach((tensor) { + _outputShapes?.add(tensor.shape); + _outputTypes?.add(tensor.type); + }); + } catch (e) { + print(e); + } + } + // 레이블 로드 + void loadLabels({List? labels}) async { + try { + _labels = + labels ?? await FileUtil.loadLabels("assets/" + LABEL_FILE_NAME); + } catch (e) { + print(e); + } + } + // 입력 이미지를 처리 + TensorImage getProcessedImage(TensorImage? inputImage) { + padSize = max(inputImage?.height ?? 0, inputImage?.width ?? 0); + + imageProcessor ??= ImageProcessorBuilder() + .add(ResizeWithCropOrPadOp(padSize ?? 0, padSize ?? 0)) + .add(ResizeOp(INPUT_SIZE, INPUT_SIZE, ResizeMethod.BILINEAR)) + .build(); + inputImage = imageProcessor?.process(inputImage!); + return inputImage!; + } + // 이미지를 예측하고 인식 결과를 반환 + Map? predict(imageLib.Image image) { + if (_interpreter == null) { + return null; + } + // 입력 이미지를 처리하고 예측 + TensorImage inputImage = TensorImage.fromImage(image); + inputImage = getProcessedImage(inputImage); + // 각 출력 텐서를 저장할 TensorBuffer 정의 + TensorBuffer outputLocations = TensorBufferFloat(_outputShapes![0]); + TensorBuffer outputClasses = TensorBufferFloat(_outputShapes![1]); + TensorBuffer outputScores = TensorBufferFloat(_outputShapes![2]); + TensorBuffer numLocations = TensorBufferFloat(_outputShapes![3]); + // 입력 이미지 + List inputs = [inputImage.buffer]; + // 출력에 해당하는 텐서 버퍼를 저장할 Map 정의 + Map outputs = { + 0: outputLocations.buffer, + 1: outputClasses.buffer, + 2: outputScores.buffer, + 3: numLocations.buffer, + }; + // 머신러닝 모델 실행 + _interpreter?.runForMultipleInputs(inputs, outputs); + int resultsCount = min(NUM_RESULTS, numLocations.getIntValue(0)); + int labelOffset = 1; + // 인식된 객체의 위치 변환 + List locations = BoundingBoxUtils.convert( + tensor: outputLocations, + valueIndex: [1, 0, 3, 2], + boundingBoxAxis: 2, + boundingBoxType: BoundingBoxType.BOUNDARIES, + coordinateType: CoordinateType.RATIO, + height: INPUT_SIZE, + width: INPUT_SIZE, + ); + // 인식 결과를 저장할 목록 정의 + List recognitions = []; + // 각 인식 결과를 Recognition 객체로 생성하고 목록에 추가 + for (int i = 0; i < resultsCount; i++) { + var score = outputScores.getDoubleValue(i); + var labelIndex = outputClasses.getIntValue(i) + labelOffset; + var label = _labels?.elementAt(labelIndex); + if (score > THRESHOLD) { + Rect? transformedRect = imageProcessor?.inverseTransformRect( + locations[i], + image.height, + image.width, + ); + + recognitions.add( + Recognition(i, label, score, transformedRect), + ); + } + } + // 인식 결과 반환 + return { + "recognitions": recognitions, + }; + } + // 인터프리터 및 레이블 getter + Interpreter? get interpreter => _interpreter; + List? get labels => _labels; +} \ No newline at end of file diff --git a/frontend/pradtice/lib/camera/image_utils.dart b/frontend/pradtice/lib/camera/image_utils.dart new file mode 100644 index 0000000000..6efb1f391e --- /dev/null +++ b/frontend/pradtice/lib/camera/image_utils.dart @@ -0,0 +1,65 @@ +import 'package:camera/camera.dart'; +import 'package:image/image.dart' as imageLib; + +// ImageUtils 클래스 +class ImageUtils { + // CameraImage 객체를 YUV420 형식에서 imageLib.Image(RGB 형식)으로 변환 + static imageLib.Image? convertCameraImage(CameraImage cameraImage) { + // 이미지 형식에 따라 변환 함수 호출 + if (cameraImage.format.group == ImageFormatGroup.yuv420) { + return convertYUV420ToImage(cameraImage); + } else if (cameraImage.format.group == ImageFormatGroup.bgra8888) { + return convertBGRA8888ToImage(cameraImage); + } else { + return null; + } + } + // CameraImage 객체를 BGRA8888 형식에서 imageLib.Image(RGB 형식)으로 변환 + static imageLib.Image convertBGRA8888ToImage(CameraImage cameraImage) { + imageLib.Image img = imageLib.Image.fromBytes( + cameraImage.planes[0].width ?? 0, + cameraImage.planes[0].height ?? 0, + cameraImage.planes[0].bytes, + format: imageLib.Format.bgra); + return img; + } + // CameraImage 객체를 YUV420 형식에서 imageLib.Image(RGB 형식)으로 변환 + static imageLib.Image convertYUV420ToImage(CameraImage cameraImage) { + // 이미지의 너비와 높이를 가져옴 + final int width = cameraImage.width; + final int height = cameraImage.height; + final int uvRowStride = cameraImage.planes[1].bytesPerRow; + final int uvPixelStride = cameraImage.planes[1].bytesPerPixel ?? 0; + final image = imageLib.Image(width, height); + // 모든 픽셀을 YUV 값을 RGB로 변 + for (int w = 0; w < width; w++) { + for (int h = 0; h < height; h++) { + final int uvIndex = + uvPixelStride * (w / 2).floor() + uvRowStride * (h / 2).floor(); + final int index = h * width + w; + final y = cameraImage.planes[0].bytes[index]; + final u = cameraImage.planes[1].bytes[uvIndex]; + final v = cameraImage.planes[2].bytes[uvIndex]; + + image.data[index] = ImageUtils.yuv2rgb(y, u, v); + } + } + return image; + } + // 단일 YUV 픽셀을 RGB로 변환 + static int yuv2rgb(int y, int u, int v) { + // YUV 픽셀 값을 RGB 값으로 변환 + int r = (y + v * 1436 / 1024 - 179).round(); + int g = (y - u * 46549 / 131072 + 44 - v * 93604 / 131072 + 91).round(); + int b = (y + u * 1814 / 1024 - 227).round(); + // RGB 값을 경계 [0, 255] 내에 있도록 설정 + r = r.clamp(0, 255); + g = g.clamp(0, 255); + b = b.clamp(0, 255); + // 최종적으로 변환된 RGB 값 반환 + return 0xff000000 | + ((b << 16) & 0xff0000) | + ((g << 8) & 0xff00) | + (r & 0xff); + } +} \ No newline at end of file diff --git a/frontend/pradtice/lib/camera/isolate_utils.dart b/frontend/pradtice/lib/camera/isolate_utils.dart new file mode 100644 index 0000000000..0066f07e26 --- /dev/null +++ b/frontend/pradtice/lib/camera/isolate_utils.dart @@ -0,0 +1,48 @@ +import 'dart:async'; +import 'dart:isolate'; +import 'package:camera/camera.dart'; +import 'package:image/image.dart' as imageLib; +import 'package:pradtice/camera/classifier.dart'; +import 'package:tflite_flutter/tflite_flutter.dart'; +import 'image_utils.dart'; + +class IsolateUtils { + Isolate? _isolate; + ReceivePort _receivePort = ReceivePort(); + SendPort? _sendPort; + SendPort? get sendPort => _sendPort; + // Isolate 시작 + Future start() async { + _isolate = await Isolate.spawn(entryPoint, _receivePort.sendPort); + _sendPort = await _receivePort.first; + } + // Isolate의 entryPoint 함수 + static void entryPoint(SendPort sendPort) async { + final port = ReceivePort(); + sendPort.send(port.sendPort); + // 전달받은 데이터를 사용하여 분류 및 추론 수행 + await for (final IsolateData isolateData in port) { + Classifier classifier = Classifier( + interpreter: Interpreter.fromAddress(isolateData.interpreterAddress), + labels: isolateData.labels); + imageLib.Image? image = + ImageUtils.convertCameraImage(isolateData.cameraImage); + image = imageLib.copyRotate(image!, 90); + Map? results = classifier.predict(image); + isolateData.responsePort?.send(results); + } + } +} +// Isolate 간에 전달할 데이터 class +class IsolateData { + CameraImage cameraImage; + int interpreterAddress; + List labels; + SendPort? responsePort; + + IsolateData( + this.cameraImage, + this.interpreterAddress, + this.labels, + ); +} \ No newline at end of file diff --git a/frontend/pradtice/lib/camera/recognition.dart b/frontend/pradtice/lib/camera/recognition.dart new file mode 100644 index 0000000000..d8b344fc22 --- /dev/null +++ b/frontend/pradtice/lib/camera/recognition.dart @@ -0,0 +1,57 @@ +import 'dart:math'; +import 'package:flutter/cupertino.dart'; +import 'package:pradtice/camera/camera_settings.dart'; + +class Recognition { + // 인식된 객체의 ID 저장 + final int? _id; + // 인식된 객체의 레이블 저장 + final String? _label; + // 인식된 객체의 확률(신뢰도) 저장 + final double? _score; + // 인식된 객체의 위치 저장 + final Rect? _location; + // Recognition 클래스 생성자 + Recognition( + this._id, + this._label, + this._score, [ + this._location, + ]); + // 각 변수에 대한 getter + int? get id => _id; + String? get label => _label; + double? get score => _score; + Rect? get location => _location; + // 객체의 위치를 화면에 맞게 변환하여 반환 + Rect get renderLocation { + // 카메라 설정에서 비율 값 + double? ratioX = CameraSettings.ratio; + double? ratioY = ratioX; + // 위치 정보를 변환하여 좌표로 계산 + double transLeft = max( + 0.1, + (location?.left ?? 0) * (ratioX ?? 0), + ); + double transTop = max( + 0.1, + (location?.top ?? 0) * (ratioY ?? 0), + ); + double transWidth = min( + (location?.width ?? 0) * (ratioX ?? 0), + CameraSettings.actualPreviewSize.width, + ); + double transHeight = min( + (location?.height ?? 0) * (ratioY ?? 0), + CameraSettings.actualPreviewSize.height, + ); + // 변환된 위치 정보를 생성하여 반환 + Rect transformedRect = Rect.fromLTWH( + transLeft, + transTop, + transWidth, + transHeight, + ); + return transformedRect; + } +} \ No newline at end of file diff --git a/frontend/pradtice/lib/flutter_vision.dart b/frontend/pradtice/lib/flutter_vision.dart new file mode 100644 index 0000000000..792ff4002f --- /dev/null +++ b/frontend/pradtice/lib/flutter_vision.dart @@ -0,0 +1,176 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:pradtice/src/plugin/android.dart'; + +abstract class FlutterVision { + factory FlutterVision() { + switch (Platform.operatingSystem) { + case 'android': + return AndroidFlutterVision(); + case 'ios': + throw UnimplementedError('iOS is not supported for now'); + //return IosDniScanner(); + default: + throw UnsupportedError('Unsupported platform'); + } + } + + // ///loadOcrModel: loads both YOLOv5 and Tesseract4 model from the assets folder and + // ///return a ResponseHandler object. + // /// + // ///if the load is successful, it returns a ResponseHandler as a success object, + // ///otherwise it returns a ResponseHandler as an error object + // ///```json:{ + // /// "type": "success" or "error", + // /// "message": "ok", + // /// "data": {}``` + // /// + // /// args: [modelPath] - path to the model file + // /// ,[labelsPath] - path to the labels file + // /// ,[numThreads] - number of threads to use for inference + // /// ,[useGPU] - use GPU for inference + // /// ,[language] - language for tesseract4(en,spa,de,fr,it,nl,ru,pt,tr,zh) + // /// ,[tesseract4Config] - tesseract4 config + // Future loadOcrModel( + // {required String modelPath, + // required String labels, + // int? numThreads, + // bool? useGpu, + // String? language, + // Map? args}); + + // ///scanOnFrame accept a byte List as input and + // ///return a ResponseHandler object. + // /// + // ///if scanOnFrame run without error, it returns a ResponseHandler as a success object, + // ///otherwise it returns a ResponseHandler as an error object. + // /// + // ///```json:{ + // /// "type": 'success', + // /// "message": "ok", + // /// "data": List> + // /// }``` + // ///where map is mapped as follows: + // /// + // ///```Map:{ + // /// "confidence": double, + // /// "box": {x1:double, y1:double, x2:double, y2:double}, + // /// "text": String, + // /// "image": Uint8List, + // /// "tag": String + // /// }``` + // /// + // ///args: [bytesList] - image as byte list + // ///, [imageHeight] - image height + // ///, [imageWidth] - image width + // ///, [classIsText] - list of classes to be detected as text + // ///, [iouThreshold] - intersection over union threshold + // ///, [confThreshold] - confidence threshold + // Future>> ocrOnFrame({ + // required List bytesList, + // required int imageHeight, + // required int imageWidth, + // required List classIsText, + // double? iouThreshold, + // double? confThreshold, + // }); + + // /// dispose OCRModel, clean and save resources + // Future closeOcrModel(); + + ///loadYoloModel: load YOLOv5 model from the assets folder + /// + /// args: [modelPath] - path to the model file + /// ,[labelsPath] - path to the labels file + /// ,[modelVersion] - yolov5, yolov8 + /// ,[quantization] - When set to true, quantized models are used, which can result in faster execution, reduced memory usage, and slightly lower accuracy. + /// ,[numThreads] - number of threads to use for inference + /// ,[useGPU] - use GPU for inference + Future loadYoloModel( + {required String modelPath, + required String labels, + required String modelVersion, + bool? quantization, + int? numThreads, + bool? useGpu}); + + ///yoloOnFrame accept a byte List as input and + ///return a List>. + /// + ///where map is mapped as follow: + /// + ///```Map:{ + /// "box": [x1:left, y1:top, x2:right, y2:bottom, class_confidence] + /// "tag": String: detected class + /// }``` + /// + ///args: [bytesList] - image as byte list + ///, [imageHeight] - image height + ///, [imageWidth] - image width + ///, [iouThreshold] - intersection over union threshold, default 0.4 + ///, [confThreshold] - model confidence threshold, default 0.5, only for [yolov5] + ///, [classThreshold] - class confidence threshold, default 0.5 + Future>> yoloOnFrame({ + required List bytesList, + required int imageHeight, + required int imageWidth, + double? iouThreshold, + double? confThreshold, + double? classThreshold, + }); + + ///yoloOnImage accept a Uint8List as input and + ///return a List>. + /// + ///where map is mapped as follows: + /// + ///```Map:{ + /// "box": [x1:left, y1:top, x2:right, y2:bottom, class_confidence] + /// "tag": String: detected class + /// }``` + /// + ///args: [bytesList] - image bytes + ///, [imageHeight] - image height + ///, [imageWidth] - image width + ///, [iouThreshold] - intersection over union threshold, default 0.4 + ///, [confThreshold] - model confidence threshold, default 0.5, only for [yolov5] + ///, [classThreshold] - class confidence threshold, default 0.5 + Future>> yoloOnImage({ + required Uint8List bytesList, + required int imageHeight, + required int imageWidth, + double? iouThreshold, + double? confThreshold, + double? classThreshold, + }); + + /// dispose OCRModel, clean and save resources + Future closeYoloModel(); + + ///loadTesseractModel: load Tesseract5 model from the assets folder. + /// + /// ,[language] - language for tesseract4(en,spa,de,fr,it,nl,ru,pt,tr,zh) + /// ,[tesseract4Config] - tesseract4 config + Future loadTesseractModel( + {String? language, Map? args}); + + ///tesseractOnImage accept a byte as input and + ///return a List. + /// + ///where map is mapped as follows: + /// + ///```Map:{ + /// "text": String + /// "word_conf": List:int + /// "mean_conf": int + /// }``` + /// + ///args: [bytesList] - image as byte + Future>> tesseractOnImage( + {required Uint8List bytesList}); + + /// dispose Tesseract model, clean and save resources + Future closeTesseractModel(); +} diff --git a/frontend/pradtice/lib/location_permission.dart b/frontend/pradtice/lib/location_permission.dart new file mode 100644 index 0000000000..d07a8c6dc9 --- /dev/null +++ b/frontend/pradtice/lib/location_permission.dart @@ -0,0 +1,43 @@ +import 'package:geolocator/geolocator.dart'; +import 'package:permission_handler/permission_handler.dart'; + +class MyLocation { + late double latitude; + late double longitude; + + Future getMyCurrentLocation() async { + // 위치권한을 가지고 있는지 확인 + var status_position = await Permission.location.status; + + if (status_position.isGranted) { + // 권한이 있는 경우, 10초마다 위치 정보를 출력합니다. + Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high); + + latitude = position.latitude; + longitude = position.longitude; + + print("위도: $latitude , 경도: $longitude"); + } else { + // 권한이 없는 경우 + print("위치 권한이 필요합니다."); + + // 위치 권한 요청 + var status_position_request = await Permission.location.request(); + + // 사용자가 권한을 허용한 경우 + if (status_position_request.isGranted) { + Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high); + + latitude = position.latitude; + longitude = position.longitude; + + print("위도: $latitude , 경도: $longitude"); + + } else { + // 사용자가 권한을 거부한 경우 + print("위치 권한이 거부되었습니다."); + } + } + } + +} diff --git a/frontend/pradtice/lib/main.dart b/frontend/pradtice/lib/main.dart new file mode 100644 index 0000000000..dde4ba9037 --- /dev/null +++ b/frontend/pradtice/lib/main.dart @@ -0,0 +1,146 @@ +import 'package:flutter/material.dart'; +import 'ObjectRecognitionMode.dart'; +import 'sever.dart'; // 서버 연동 파일 import +import 'dart:async'; //탭 시간차 패키지 +import 'package:speech_to_text/speech_recognition_result.dart'; // 음성 인식 패키지 +import 'package:speech_to_text/speech_to_text.dart'; // stt -> tts 패키지 +import 'STT.dart'; //음성인식 패키지 +import 'package:permission_handler/permission_handler.dart'; + +// import 'Tmap.dart'; +import 'GoogleMap.dart'; +import 'TextToSpeech.dart'; + + +void main() { + runApp( + MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home : MyApp() + ) + ); +} + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MyHomePage(); + } +} + +class MyHomePage extends StatefulWidget { + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + + //sever.dart 에서의 Sever 클래스 상속 + Sever sever = Sever(); + TTS tts = TTS(message: '기본'); + + // GoogleMap.dart 에서의 GoogleMap 클래스 상속 + MyGoogleMap mygoogleMap = MyGoogleMap(); + //앱 실행시 백그라운드 실행 + + @override + void initState() { + super.initState(); + requestPermissions(); //권한 허가 + tts.setMessage('화면을 탭하세요'); + tts.speak(); + } + + //권한 허가 + Future requestPermissions() async { + Map statuses = await [ + Permission.location, + Permission.camera, + Permission.microphone, + + ].request(); + + final locationStatus = statuses[Permission.location]; + final cameraStatus = statuses[Permission.camera]; + final micStatus = statuses[Permission.microphone]; + + print('위치 권한: $locationStatus'); + print('카메라 권한: $cameraStatus'); + print('마이크 권한: $micStatus'); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // _tapCount 변수를 사용하지 않고 바로 Navigator.push를 사용하여 + // 싱글 탭 이벤트 처리 시 SttTab() 호출 + Navigator.push( + context, + MaterialPageRoute(builder: (context) => SttTab()), + ); + }, + child: Scaffold( + appBar: AppBar( + backgroundColor: Colors.blueGrey, + bottom: PreferredSize( + preferredSize: Size.fromHeight(4.0), // 밑줄의 높이 설정 + child: Container( + color: Colors.black, // 밑줄의 색상 설정 + height: 0, // 밑줄의 두께 설정 + ), + ), + ), + + backgroundColor: Colors.blueGrey, // Scaffold의 배경색을 설정 + body:Container( + color: Colors.blueGrey, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 150.0), // 마이크 아이콘과 모드 버튼들 사이의 간격을 조정 + child: Center( + child: Image.asset('assets/eye_u_mono.png'), + // child: ElevatedButton( + // onPressed: (){ + // Navigator.push(context, + // MaterialPageRoute(builder: (context) => SttTab()), + // ); + // }, + // style: ElevatedButton.styleFrom( + // shape: CircleBorder(), // 버튼을 원형으로 만듦 + // padding: EdgeInsets.all(20), // 원형 버튼 내부의 아이콘과의 padding + // ), + // child: Icon(Icons.mic, size: 40.0,color: Colors.blueGrey,), // 아이콘 크기를 조정하여 화면 비중 감소 + // ), + ), + ), + ], + ), + ) + + + + ), + ); + } +} + +class ConvenienceMode extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('편의 기능 모드'), + ), + body: Center( + child: Text('여기에 편의 기능 모드의 기능을 구현해주세요.'), + ), + ); + } +} diff --git a/frontend/pradtice/lib/sever.dart b/frontend/pradtice/lib/sever.dart new file mode 100644 index 0000000000..d473014e2e --- /dev/null +++ b/frontend/pradtice/lib/sever.dart @@ -0,0 +1,623 @@ +//메인.dart에도 밑의 2개 패키지 설치 요함 +import 'package:http/http.dart' as http; // http 사용 패키지 +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:pradtice/location_permission.dart'; //json 변환 패키지 +import 'dart:async'; +import 'GetAndroidID.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'STT.dart'; +import 'package:flutter_compass/flutter_compass.dart'; +import 'TextToSpeech.dart'; +import 'ObjectRecognitionMode.dart'; +String Adress = ''; +String nodeLat = ''; +String nodeLon = ''; +int IdxNode = 0; +int difNode = 0; +bool checkdir = false; +class NaviTap extends StatefulWidget { + const NaviTap({super.key}); + + @override + State createState() => _NaviTapState(); +} + +class _NaviTapState extends State { + Sever sever = Sever(); + Timer? timer; + + @override + void initState() { + super.initState(); + sever.onLocationChanged = () { + setState(() {}); // 위치 정보가 변경될 때마다 UI 업데이트 + }; + } + + @override + void dispose() { + timer?.cancel(); // 위젯이 사라질 때 타이머를 취소 + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text('목적지 : ${Adress}')), + body: Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Wrap( + spacing: 70.0, // 가로 간격 + runSpacing: 50.0, // 세로 간격 + alignment: WrapAlignment.center, + children: [ + ElevatedButton(onPressed: (){ + setState(() { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => SttAdress()), + ); + print(Adress); + }); + }, child: Text('목적지 설정')) + ,ElevatedButton(onPressed: () { + sever.start_navi(); + }, child: Text('Start-navi')), + ElevatedButton(onPressed: () { + sever.current_location(); + }, child: Text('Current-location')), + ElevatedButton(onPressed: () { + sever.canceltimer();// 타이머 취소 + sever.cancel_navi(); + }, child: Text('Cancel-navi')), + Text('${sever.distance}M'), + Text('IdxNode : $IdxNode'), + Text(sever.description), + Text(sever.dirmsg), + Text('${sever.cnt}'), + ElevatedButton(onPressed: () { + Navigator.push(context, + MaterialPageRoute(builder: (context) => testmap()), + ); + }, child: Text('Map')), + ElevatedButton(onPressed: (){ + setState(() { + }); + }, child: Text('꾹')) + ] + ) + ], + ), + ), + ); + } +} + +class Sever { + MyLocation myLocation = MyLocation(); + Timer? timer; + Timer? timer1; + + double Lat = 0; + double Lon = 0; + int cnt = 0; + + var description = '방향을 지정합니다'; + var distance = '0'; + var uuid = ''; + var dir = ''; + var dirmsg = '방향메세지'; + + GetID getID = GetID(); + Compass compass = Compass(); + TTS tts = TTS(message: ''); + TTS tts1 = TTS(message: ''); + // 콜백 함수를 위한 정의 + Function? onLocationChanged; + + setid() { + uuid = getID.id; + print('uuid = $uuid'); + } + + setAdress(String adress){ + Adress = adress; + } + ttsread(){ + tts.speak(); + } + canceltimer(){ + timer?.cancel(); + timer1?.cancel(); + } + + Future start_navi() async { + setid(); + await updateLocation(); + sendStartNaviRequest(); + direct_().then((_){ + if(checkdir==true){ + tts1.setMessage('화면을 탭하세요'); + tts1.speak(); + } + }); + } + + Future current_location() async { + difNode=IdxNode; + if (timer1 != null && timer1!.isActive) { + timer1?.cancel(); + } + timer1 = Timer.periodic(Duration(seconds: 3), (Timer t) async { + await updateLocation(); + sendCurrentLocationRequest(); + }); + } + + Future cancel_navi() async { + timer1?.cancel(); + sendCancelNaviRequest(); + } + + Future direct_() async{ + checkdir=false; + timer = Timer.periodic(Duration(seconds: 3), (Timer t) async { + cnt=0; + await updateLocation(); + dir = compass.direct; + sendDirect_().then((_){ + if(dirmsg == '해당 방향으로 진행하세요'){ + timer?.cancel(); + tts1.speak(); + checkdir=true; + } + }); + }); + } + + Future updateLocation() async { + await myLocation.getMyCurrentLocation(); + Lat = myLocation.latitude; + Lon = myLocation.longitude; + print("위도 : $Lat 경도 : $Lon"); + } + + // 서버에 시작 위치 전송 + Future sendStartNaviRequest() async { + var url = Uri.parse('http://15.164.219.111:8080/start-navi?startLat=$Lat&startLon=$Lon&endAddress=$Adress&uuid=$uuid'); + try { + var response = await http.get(url); + if (response.statusCode == 200) { + print("전송 완료"); + var responseBody = utf8.decode(response.bodyBytes); + var jsonResponse = jsonDecode(responseBody); + print(jsonResponse); + IdxNode = jsonResponse['pointIndex']; + description = jsonResponse['description']; + cnt=0; + } else { + print("서버 전송 실패"); + } + } catch (e) { + print("에러코드 : $e"); + } + } + + // 서버에 현재 위치 전송 + Future sendCurrentLocationRequest() async { + + var url = Uri.parse('http://15.164.219.111:8080/current-location?curLat=$Lat&curLon=$Lon&uuid=$uuid&pointIndex=$IdxNode&cnt=$cnt&distance=$distance'); + try { + var response = await http.get(url); + if (response.statusCode == 200) { + print("전송 완료"); + var responseBody = utf8.decode(response.bodyBytes); + var jsonResponse = jsonDecode(responseBody); + print(jsonResponse); + IdxNode = jsonResponse['pointIndex']; + distance = jsonResponse['distance']; + nodeLat = jsonResponse['lat']; + nodeLon = jsonResponse['lon']; + cnt = jsonResponse['cnt']; + if(difNode != IdxNode){ + timer1?.cancel(); + direct_().then((_){ + current_location(); + }); + } + if(jsonResponse['description']!= '이동중'){ + description = jsonResponse['description']; + if(description == '도착'){ + timer1?.cancel(); + cancel_navi().then((_){ + tts.setMessage('목적지에 도착했습니다. 경로안내를 종료합니다'); + tts.speak(); + }); + } + if(description == '재탐색'){ + timer1?.cancel(); + timer?.cancel(); + tts.setMessage('경로를 재탐색 합니다.'); + tts.speak(); + cancel_navi().then((_){ + start_navi(); + }); + } + tts.setMessage(description); + tts.speak(); + } + } else { + print("서버에 전송 실패"); + } + } catch (e) { + print("에러코드 : $e"); + } + } + + // 서버에 내비게이션 취소 요청 전송 + Future sendCancelNaviRequest() async { + var url = Uri.parse('http://15.164.219.111:8080/cancel-navi?uuid=$uuid'); + try { + var response = await http.get(url); + if (response.statusCode == 200) { + print("전송 완료"); + print(response.body); + } else { + print("서버 전송 실패"); + } + } catch (e) { + print("에러코드 : $e"); + } + } + + Future sendDirect_() async { + var url = Uri.parse('http://15.164.219.111:8080/direction?curLat=$Lat&curLon=$Lon&uuid=$uuid&pointIndex=$IdxNode&curDir=$dir'); + try { + var response = await http.get(url); + if (response.statusCode == 200) { + print("전송 완료"); + var responseBody = utf8.decode(response.bodyBytes); + var jsonResponse = jsonDecode(responseBody); + print(jsonResponse); + dirmsg = jsonResponse['dirMsg']; + tts1.setMessage(dirmsg); + tts1.speak(); + } else { + print("서버 전송 실패"); + } + } catch (e) { + print("에러코드 : $e"); + } + } + +} + +class testmap extends StatefulWidget { + @override + _testmapState createState() => _testmapState(); +} + +class _testmapState extends State { + GoogleMapController? mapController; // GoogleMap 컨트롤러 + Set markers = {}; // 마커를 관리할 Set + // 임시로 초기 위치를 설정합니다. 나중에 실제 데이터로 업데이트해야 합니다. + + final LatLng _center = const LatLng(37.5665, 126.9780); + + void _onMapCreated(GoogleMapController controller) { + mapController = controller; + _updateMarkers(); // 맵이 생성될 때 마커 업데이트 + } + + // 마커를 업데이트하는 함수 + void _updateMarkers() async { + + double lat = double.parse(nodeLat); + double lon = double.parse(nodeLon); // 예시 경도 + + // 마커 Set을 업데이트합니다. + setState(() { + markers.clear(); // 기존 마커를 지우고 새로운 위치에 마커를 추가합니다. + markers.add( + Marker( + markerId: MarkerId('$IdxNode'), + position: LatLng(lat, lon), + + ), + ); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Google Maps Sample App'), + ), + body: GoogleMap( + myLocationEnabled: true, + onMapCreated: _onMapCreated, + initialCameraPosition: CameraPosition( + target: _center, + zoom: 11.0, + ), + markers: markers, + ), + floatingActionButton: FloatingActionButton.extended( + onPressed: _updateMarkers, // 버튼을 누를 때마다 마커 업데이트 + label: Icon(Icons.location_on), + ), + ); + } +} + +class Compass { + String direct = '??'; + + Compass(){ + initState(); + } + void printdire() { + print(direct); +} + void initState(){ + FlutterCompass.events!.listen((CompassEvent event) { + direct = getDirect(event.heading); + }); + } + + String getDirect(double? varangle) { + if (varangle == null) { + return '??'; + } + double angle = varangle + 180; + angle = angle % 360; // Ensure the angle is within 0 to 360 degrees + + if (angle >= 22.5 && angle < 112.5) { + return 'W'; + } else if (angle >= 112.5 && angle < 202.5) { + return 'N'; + } else if (angle >= 202.5 && angle < 292.5) { + return 'E'; + } else if ((angle >= 292.5 && angle < 360) || (angle >= 0 && angle < 22.5)) { + return 'S'; + } else { + return '??'; + } + } +} + + + + + + + + + + + +// class NaviTap extends StatefulWidget { +// const NaviTap({super.key}); +// +// @override +// State createState() => _NaviTapState(); +// } +// +// class _NaviTapState extends State { +// Sever sever = Sever(); +// Timer? timer; +// +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// appBar: AppBar(title: Text('내비게이션'),), +// body:Container( +// child: Column( +// mainAxisAlignment: MainAxisAlignment.center, +// crossAxisAlignment: CrossAxisAlignment.center, +// children: [ +// Wrap( +// spacing: 70.0, // 가로 간격 +// runSpacing: 50.0, // 세로 간격 +// alignment: WrapAlignment.center, +// children: [ +// ElevatedButton(onPressed: (){ +// setState(() { +// sever.start_navi(); +// setState(() { +// }); +// }); +// }, child: Text('Start-navi')), +// ElevatedButton(onPressed: (){ +// timer?.cancel(); // 실행 중인 타이머가 있다면 취소 +// // 새로운 타이머 생성 및 시작 +// timer = Timer.periodic(Duration(seconds: 5), (Timer t) { +// setState(() { +// sever.current_location(); +// }); +// }); +// }, child: Text('Current-location')), +// ElevatedButton(onPressed: (){ +// timer?.cancel(); // 타이머 취소 +// setState(() { +// sever.cancel_navi(); +// }); +// }, child: Text('Cancel-navi')), +// Text(sever.distance+'M'), +// Text('IdxNode : ${sever.IdxNode}'), +// Text(sever.description), +// ElevatedButton(onPressed: (){ +// Navigator.push(context, +// MaterialPageRoute(builder: (context) => testmap()), +// ); +// }, child: Text('Map')) +// ] +// ) +// ], +// ), +// ), +// ); +// } +// } +// +// +// +// class Sever { +// +// MyLocation myLocation = MyLocation(); +// +// double Lat = 0; +// double Lon = 0; +// String nodeLat ='37.470629'; +// String nodeLon = '127.126781'; +// String Adress = '국민대'; +// int IdxNode = 0; +// var description = '현재 경로'; +// var distance = '0'; +// var uuid = ''; +// +// GetID getID = GetID(); +// +// setid(){ +// uuid = getID.id; +// print('uuid = $uuid'); +// } +// +// +// Future start_navi() async { +// setid(); +// myLocation.getMyCurrentLocation(); +// Lat = myLocation.latitude; +// Lon = myLocation.longitude; +// var url = Uri.parse('http://15.164.219.111:8080/start-navi?startLat=$Lat&startLon=$Lon&endAddress=$Adress&uuid=$uuid'); +// try{ +// var response = await http.get(url); +// if (response.statusCode != 200) { +// print("서버 전송 실패"); +// } else { +// print("전송 완료"); +// var responseBody = utf8.decode(response.bodyBytes); +// var jsonResponse = jsonDecode(responseBody); +// print(jsonResponse); +// IdxNode = jsonResponse['pointIndex']; +// description = jsonResponse['description']; +// +// } +// }catch(e){ +// print("에러코드 : $e"); +// } +// } +// +// Future current_location() async { +// myLocation.getMyCurrentLocation(); +// Lat = myLocation.latitude; +// Lon = myLocation.longitude; +// print("위도 : $Lat 경도 : $Lon"); +// var url = Uri.parse('http://15.164.219.111:8080/current-location?curLat=$Lat&curLon=$Lon&uuid=$uuid&pointIndex=$IdxNode'); +// try{ +// var response = await http.get(url); +// if (response.statusCode != 200) { +// // 요청이 성공하면 응답을 출력합니다. +// print("서버에 전송 실패"); +// } else { +// print("전송 완료"); +// var responseBody = utf8.decode(response.bodyBytes); +// var jsonResponse = jsonDecode(responseBody); +// print(jsonResponse); +// IdxNode = jsonResponse['pointIndex']; +// description = jsonResponse['description']; +// distance = jsonResponse['distance']; +// nodeLat = jsonResponse['lat']; +// nodeLon = jsonResponse['lon']; +// } +// }catch(e){ +// print("에러코드 : $e"); +// } +// } +// +// Future cancel_navi() async { +// try{ +// var url = Uri.parse('http://15.164.219.111:8080/cancel-navi?uuid=$uuid'); +// var response = await http.get(url); +// if ( response.statusCode != 200){ +// print("서버 전송 실패"); +// } else { +// print("전송 완료"); +// print(response.body); +// } +// }catch(e){ +// print("에러코드 : $e"); +// } +// } +// +// } + +// class testmap extends StatefulWidget { +// const testmap({super.key}); +// +// @override +// State createState() => _testmapState(); +// } +// +// class _testmapState extends State { +// +// Completer _controller = Completer(); +// Set _markers = {}; +// Sever sever = Sever(); +// +// @override +// void initState() { +// super.initState(); +// loca(); +// } +// +// Future loca() async { +// setState(() { +// _centerloca(LatLng(sever.Lat, sever.Lon)); +// nodeloca(LatLng(double.parse(sever.nodeLat),double.parse(sever.nodeLon))); +// }); +// } +// void _centerloca(LatLng posi){ +// setState(() { +// _center = CameraPosition( +// target: posi, +// zoom: 14 +// ); +// }); +// } +// void nodeloca(LatLng posi){ +// setState(() { +// nodeloc = CameraPosition( +// target:posi, +// zoom: 14 +// ); +// }); +// } +// CameraPosition _center = CameraPosition( +// target:LatLng(37.4645493,127.80803), +// zoom: 14 +// ); +// CameraPosition nodeloc = CameraPosition( +// target: LatLng(37.5665, 126.9780), +// zoom: 14 +// ); +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// body: GoogleMap(myLocationEnabled: true, +// initialCameraPosition: _center, +// markers: { +// Marker( +// markerId: MarkerId('IdxNode : ${sever.IdxNode}'), +// position: LatLng(double.parse(sever.nodeLat),double.parse(sever.nodeLon)) +// ) +// } +// ), +// ); +// } +// } diff --git a/frontend/pradtice/lib/src/plugin/android.dart b/frontend/pradtice/lib/src/plugin/android.dart new file mode 100644 index 0000000000..c13f298c1c --- /dev/null +++ b/frontend/pradtice/lib/src/plugin/android.dart @@ -0,0 +1,245 @@ +import 'dart:typed_data'; + +import '../../flutter_vision.dart'; +import 'base.dart'; + +class AndroidFlutterVision extends BaseFlutterVision implements FlutterVision { + // @override + // Future loadOcrModel( + // {required String modelPath, + // required String labels, + // int? numThreads, + // bool? useGpu, + // String? language, + // Map? args}) async { + // try { + // final String testData = await loadTessData(); + // await channel.invokeMethod('loadOcrModel', { + // 'model_path': modelPath, + // 'is_asset': true, + // 'num_threads': numThreads ?? 1, + // 'use_gpu': useGpu ?? false, + // 'label_path': labels, + // 'image_mean': 0.0, + // 'image_std': 255.0, + // 'rotation': 90, + // 'tess_data': testData, + // 'arg': args, + // 'language': language ?? 'eng' + // }); + // } catch (e) { + // rethrow; + // } + // } + + // @override + // Future>> ocrOnFrame({ + // required List bytesList, + // required int imageHeight, + // required int imageWidth, + // required List classIsText, + // double? iouThreshold, + // double? confThreshold, + // }) async { + // try { + // return await _ocrOnFrame( + // bytesList: bytesList, + // imageHeight: imageHeight, + // imageWidth: imageWidth, + // iouThreshold: iouThreshold ?? 0.4, + // confThreshold: confThreshold ?? 0.5, + // classIsText: classIsText); + // } catch (e) { + // rethrow; + // } + // } + + // Future>> _ocrOnFrame({ + // required List bytesList, + // required int imageHeight, + // required int imageWidth, + // required double iouThreshold, + // required double confThreshold, + // required List classIsText, + // }) async { + // try { + // final x = await channel.invokeMethod>>( + // 'ocrOnFrame', + // { + // "bytesList": bytesList, + // "image_height": imageHeight, + // "image_width": imageWidth, + // "iou_threshold": iouThreshold, + // "conf_threshold": confThreshold, + // "class_is_text": classIsText + // }, + // ); + // return x ?? []; + // } catch (e) { + // rethrow; + // } + // } + + @override + Future loadYoloModel( + {required String modelPath, + required String labels, + required String modelVersion, + bool? quantization, + int? numThreads, + bool? useGpu}) async { + try { + await channel.invokeMethod('loadYoloModel', { + 'model_path': modelPath, + 'is_asset': true, + 'quantization': quantization ?? false, + 'num_threads': numThreads ?? 1, + 'use_gpu': useGpu ?? false, + 'label_path': labels, + 'rotation': 90, + 'model_version': modelVersion + }); + } catch (e) { + rethrow; + } + } + + @override + Future>> yoloOnFrame({ + required List bytesList, + required int imageHeight, + required int imageWidth, + double? iouThreshold, + double? confThreshold, + double? classThreshold, + }) async { + try { + return (await _yoloOnFrame( + bytesList: bytesList, + imageHeight: imageHeight, + imageWidth: imageWidth, + iouThreshold: iouThreshold ?? 0.4, + confThreshold: confThreshold ?? 0.5, + classThreshold: classThreshold ?? 0.5)); + } catch (e) { + rethrow; + } + } + + Future>> _yoloOnFrame({ + required List bytesList, + required int imageHeight, + required int imageWidth, + required double iouThreshold, + required double confThreshold, + required double classThreshold, + }) async { + try { + final x = await channel.invokeMethod>( + 'yoloOnFrame', + { + "bytesList": bytesList, + "image_height": imageHeight, + "image_width": imageWidth, + "iou_threshold": iouThreshold, + "conf_threshold": confThreshold, + "class_threshold": classThreshold + }, + ); + return x?.isNotEmpty ?? false + ? x!.map((e) => Map.from(e)).toList() + : []; + } catch (e) { + // print(e); + rethrow; + } + } + + @override + Future>> yoloOnImage({ + required Uint8List bytesList, + required int imageHeight, + required int imageWidth, + double? iouThreshold, + double? confThreshold, + double? classThreshold, + }) async { + try { + return await _yoloOnImage( + bytesList: bytesList, + imageHeight: imageHeight, + imageWidth: imageWidth, + iouThreshold: iouThreshold ?? 0.4, + confThreshold: confThreshold ?? 0.5, + classThreshold: classThreshold ?? 0.5); + } catch (e) { + rethrow; + } + } + + Future>> _yoloOnImage({ + required Uint8List bytesList, + required int imageHeight, + required int imageWidth, + required double iouThreshold, + required double confThreshold, + required double classThreshold, + }) async { + try { + final x = await channel.invokeMethod>( + 'yoloOnImage', + { + "bytesList": bytesList, + "image_height": imageHeight, + "image_width": imageWidth, + "iou_threshold": iouThreshold, + "conf_threshold": confThreshold, + "class_threshold": classThreshold + }, + ); + return x?.isNotEmpty ?? false + ? x!.map((e) => Map.from(e)).toList() + : []; + } catch (e) { + rethrow; + } + } + + @override + Future loadTesseractModel( + {String? language, Map? args}) async { + try { + final String testData = await loadTessData(); + await channel.invokeMethod('loadTesseractModel', + {'tess_data': testData, 'arg': args, 'language': language ?? 'eng'}); + } catch (e) { + rethrow; + } + } + + @override + Future>> tesseractOnImage({ + required Uint8List bytesList, + }) async { + try { + return await _tesseractOnImage(bytesList: bytesList); + } catch (e) { + rethrow; + } + } + + Future>> _tesseractOnImage( + {required Uint8List bytesList}) async { + try { + final x = await channel.invokeMethod( + 'tesseractOnImage', + { + "bytesList": bytesList, + }, + ); + return x == null ? [] : [Map.from(x)]; + } catch (e) { + rethrow; + } + } +} diff --git a/frontend/pradtice/lib/src/plugin/base.dart b/frontend/pradtice/lib/src/plugin/base.dart new file mode 100644 index 0000000000..0245f4def3 --- /dev/null +++ b/frontend/pradtice/lib/src/plugin/base.dart @@ -0,0 +1,106 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:path/path.dart'; +import 'package:flutter/services.dart'; +import 'package:path_provider/path_provider.dart'; + +abstract class BaseFlutterVision { + // ignore: constant_identifier_names + static const String TESS_DATA_CONFIG = 'assets/tessdata_config.json'; + // ignore: constant_identifier_names + static const String TESS_DATA_PATH = 'assets/tessdata'; + static const MethodChannel _channel = MethodChannel('flutter_vision'); + MethodChannel get channel => _channel; + + Future loadTessData() async { + try { + final Directory appDirectory = await getApplicationDocumentsDirectory(); + final String tessdataDirectory = join(appDirectory.path, 'tessdata'); + + if (!await Directory(tessdataDirectory).exists()) { + await Directory(tessdataDirectory).create(); + } + await copyTessDataToAppDocumentsDirectory(tessdataDirectory); + return appDirectory.path; + } catch (e) { + rethrow; + } + } + + Future copyTessDataToAppDocumentsDirectory(String tessdataDirectory) async { + final String config = await rootBundle.loadString(TESS_DATA_CONFIG); + Map files = jsonDecode(config); + for (var file in files["files"]) { + if (!await File('$tessdataDirectory/$file').exists()) { + final ByteData data = await rootBundle.load('$TESS_DATA_PATH/$file'); + final Uint8List bytes = data.buffer.asUint8List( + data.offsetInBytes, + data.lengthInBytes, + ); + await File('$tessdataDirectory/$file').writeAsBytes(bytes); + } + } + } + + // Future loadOcrModel( + // {required String modelPath, + // required String labels, + // int? numThreads, + // bool? useGpu, + // String? language, + // Map? args}); + + // Future>> ocrOnFrame({ + // required List bytesList, + // required int imageHeight, + // required int imageWidth, + // required List classIsText, + // double? iouThreshold, + // double? confThreshold, + // }); + + // Future closeOcrModel() async { + // await channel.invokeMethod('closeOcrModel'); + // } + + Future loadYoloModel({ + required String modelPath, + required String labels, + required String modelVersion, + bool? quantization, + int? numThreads, + bool? useGpu, + }); + + Future>> yoloOnFrame({ + required List bytesList, + required int imageHeight, + required int imageWidth, + double? iouThreshold, + double? confThreshold, + double? classThreshold, + }); + + Future>> yoloOnImage({ + required Uint8List bytesList, + required int imageHeight, + required int imageWidth, + double? iouThreshold, + double? confThreshold, + double? classThreshold, + }); + + Future closeYoloModel() async { + await channel.invokeMethod('closeYoloModel'); + } + + Future loadTesseractModel( + {String? language, Map? args}); + + Future>> tesseractOnImage( + {required Uint8List bytesList}); + + Future closeTesseractModel() async { + await channel.invokeMethod('closeTesseractModel'); + } +} diff --git a/frontend/pradtice/linux/.gitignore b/frontend/pradtice/linux/.gitignore new file mode 100644 index 0000000000..d3896c9844 --- /dev/null +++ b/frontend/pradtice/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/frontend/pradtice/linux/CMakeLists.txt b/frontend/pradtice/linux/CMakeLists.txt new file mode 100644 index 0000000000..17d5f0ed4c --- /dev/null +++ b/frontend/pradtice/linux/CMakeLists.txt @@ -0,0 +1,145 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "pradtice") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.pradtice") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/frontend/pradtice/linux/flutter/CMakeLists.txt b/frontend/pradtice/linux/flutter/CMakeLists.txt new file mode 100644 index 0000000000..d5bd01648a --- /dev/null +++ b/frontend/pradtice/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/frontend/pradtice/linux/flutter/generated_plugin_registrant.cc b/frontend/pradtice/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000000..df29d055cb --- /dev/null +++ b/frontend/pradtice/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,19 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); + g_autoptr(FlPluginRegistrar) tflite_flutter_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "TfliteFlutterPlugin"); + tflite_flutter_plugin_register_with_registrar(tflite_flutter_registrar); +} diff --git a/frontend/pradtice/linux/flutter/generated_plugin_registrant.h b/frontend/pradtice/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000000..e0f0a47bc0 --- /dev/null +++ b/frontend/pradtice/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/frontend/pradtice/linux/flutter/generated_plugins.cmake b/frontend/pradtice/linux/flutter/generated_plugins.cmake new file mode 100644 index 0000000000..de1944f6ce --- /dev/null +++ b/frontend/pradtice/linux/flutter/generated_plugins.cmake @@ -0,0 +1,25 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux + tflite_flutter +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/frontend/pradtice/linux/main.cc b/frontend/pradtice/linux/main.cc new file mode 100644 index 0000000000..e7c5c54370 --- /dev/null +++ b/frontend/pradtice/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/frontend/pradtice/linux/my_application.cc b/frontend/pradtice/linux/my_application.cc new file mode 100644 index 0000000000..d7b9740fec --- /dev/null +++ b/frontend/pradtice/linux/my_application.cc @@ -0,0 +1,124 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "pradtice"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "pradtice"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/frontend/pradtice/linux/my_application.h b/frontend/pradtice/linux/my_application.h new file mode 100644 index 0000000000..72271d5e41 --- /dev/null +++ b/frontend/pradtice/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/frontend/pradtice/macos/.gitignore b/frontend/pradtice/macos/.gitignore new file mode 100644 index 0000000000..746adbb6b9 --- /dev/null +++ b/frontend/pradtice/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/frontend/pradtice/macos/Flutter/Flutter-Debug.xcconfig b/frontend/pradtice/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000000..4b81f9b2d2 --- /dev/null +++ b/frontend/pradtice/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/frontend/pradtice/macos/Flutter/Flutter-Release.xcconfig b/frontend/pradtice/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000000..5caa9d1579 --- /dev/null +++ b/frontend/pradtice/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/frontend/pradtice/macos/Flutter/GeneratedPluginRegistrant.swift b/frontend/pradtice/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 0000000000..94bb9b0bec --- /dev/null +++ b/frontend/pradtice/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,22 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import device_info_plus +import file_selector_macos +import flutter_tts +import geolocator_apple +import path_provider_foundation +import speech_to_text_macos + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + FlutterTtsPlugin.register(with: registry.registrar(forPlugin: "FlutterTtsPlugin")) + GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SpeechToTextMacosPlugin.register(with: registry.registrar(forPlugin: "SpeechToTextMacosPlugin")) +} diff --git a/frontend/pradtice/macos/Podfile b/frontend/pradtice/macos/Podfile new file mode 100644 index 0000000000..c795730db8 --- /dev/null +++ b/frontend/pradtice/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/frontend/pradtice/macos/Runner.xcodeproj/project.pbxproj b/frontend/pradtice/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..4893b1ee34 --- /dev/null +++ b/frontend/pradtice/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,705 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* pradtice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "pradtice.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* pradtice.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* pradtice.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pradtice.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/pradtice"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pradtice.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/pradtice"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pradtice.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/pradtice"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/frontend/pradtice/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/pradtice/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/frontend/pradtice/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/frontend/pradtice/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/frontend/pradtice/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000000..869df84779 --- /dev/null +++ b/frontend/pradtice/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/pradtice/macos/Runner.xcworkspace/contents.xcworkspacedata b/frontend/pradtice/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..1d526a16ed --- /dev/null +++ b/frontend/pradtice/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/frontend/pradtice/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/pradtice/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/frontend/pradtice/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/frontend/pradtice/macos/Runner/AppDelegate.swift b/frontend/pradtice/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000000..d53ef64377 --- /dev/null +++ b/frontend/pradtice/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..a2ec33f19f --- /dev/null +++ b/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000000..82b6f9d9a3 Binary files /dev/null and b/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000000..13b35eba55 Binary files /dev/null and b/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000000..0a3f5fa40f Binary files /dev/null and b/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 0000000000..bdb57226d5 Binary files /dev/null and b/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 0000000000..f083318e09 Binary files /dev/null and b/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 0000000000..326c0e72c9 Binary files /dev/null and b/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000000..2f1632cfdd Binary files /dev/null and b/frontend/pradtice/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/frontend/pradtice/macos/Runner/Base.lproj/MainMenu.xib b/frontend/pradtice/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 0000000000..80e867a4e0 --- /dev/null +++ b/frontend/pradtice/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/pradtice/macos/Runner/Configs/AppInfo.xcconfig b/frontend/pradtice/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000000..b64656ea1e --- /dev/null +++ b/frontend/pradtice/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = pradtice + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.pradtice + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2024 com.example. All rights reserved. diff --git a/frontend/pradtice/macos/Runner/Configs/Debug.xcconfig b/frontend/pradtice/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000000..36b0fd9464 --- /dev/null +++ b/frontend/pradtice/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/frontend/pradtice/macos/Runner/Configs/Release.xcconfig b/frontend/pradtice/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000000..dff4f49561 --- /dev/null +++ b/frontend/pradtice/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/frontend/pradtice/macos/Runner/Configs/Warnings.xcconfig b/frontend/pradtice/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000000..42bcbf4780 --- /dev/null +++ b/frontend/pradtice/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/frontend/pradtice/macos/Runner/DebugProfile.entitlements b/frontend/pradtice/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000000..dddb8a30c8 --- /dev/null +++ b/frontend/pradtice/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/frontend/pradtice/macos/Runner/Info.plist b/frontend/pradtice/macos/Runner/Info.plist new file mode 100644 index 0000000000..4789daa6a4 --- /dev/null +++ b/frontend/pradtice/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/frontend/pradtice/macos/Runner/MainFlutterWindow.swift b/frontend/pradtice/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000000..3cc05eb234 --- /dev/null +++ b/frontend/pradtice/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/frontend/pradtice/macos/Runner/Release.entitlements b/frontend/pradtice/macos/Runner/Release.entitlements new file mode 100644 index 0000000000..852fa1a472 --- /dev/null +++ b/frontend/pradtice/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/frontend/pradtice/macos/RunnerTests/RunnerTests.swift b/frontend/pradtice/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000000..5418c9f539 --- /dev/null +++ b/frontend/pradtice/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import FlutterMacOS +import Cocoa +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/frontend/pradtice/pubspec.lock b/frontend/pradtice/pubspec.lock new file mode 100644 index 0000000000..6f6f16dfde --- /dev/null +++ b/frontend/pradtice/pubspec.lock @@ -0,0 +1,1138 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + url: "https://pub.dev" + source: hosted + version: "67.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + url: "https://pub.dev" + source: hosted + version: "6.4.1" + android_id: + dependency: "direct main" + description: + name: android_id + sha256: "5c2d3a259afcd173dbe367ba452817bd530c4df75d251d652c69b8d3c8ac0d36" + url: "https://pub.dev" + source: hosted + version: "0.3.6" + archive: + dependency: transitive + description: + name: archive + sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" + url: "https://pub.dev" + source: hosted + version: "3.4.10" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb + url: "https://pub.dev" + source: hosted + version: "8.9.2" + camera: + dependency: "direct main" + description: + name: camera + sha256: "3ad71371b8168a4c8012c0b40a53c05afc75d46cc688b0f37b4611a841d47b25" + url: "https://pub.dev" + source: hosted + version: "0.9.8+1" + camera_android: + dependency: transitive + description: + name: camera_android + sha256: "665d62c1f334722c7519ca5d3b94ad68ecaa801691870602da5638a42c1fff67" + url: "https://pub.dev" + source: hosted + version: "0.9.8+3" + camera_avfoundation: + dependency: transitive + description: + name: camera_avfoundation + sha256: "138242ed4e3030c2738ca70858e56714deb087c2f8ce8226c0aa61208f075882" + url: "https://pub.dev" + source: hosted + version: "0.9.15+2" + camera_platform_interface: + dependency: transitive + description: + name: camera_platform_interface + sha256: a250314a48ea337b35909a4c9d5416a208d736dcb01d0b02c6af122be66660b0 + url: "https://pub.dev" + source: hosted + version: "2.7.4" + camera_web: + dependency: transitive + description: + name: camera_web + sha256: "18cdbee5441e9a6fb129fdd9b68a06d1b8c5236932ba97d5faeaefe80db2e5bd" + url: "https://pub.dev" + source: hosted + version: "0.2.1+6" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 + url: "https://pub.dev" + source: hosted + version: "4.10.0" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" + url: "https://pub.dev" + source: hosted + version: "1.7.2" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" + url: "https://pub.dev" + source: hosted + version: "0.3.4+1" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + csslib: + dependency: transitive + description: + name: csslib + sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d + url: "https://pub.dev" + source: hosted + version: "1.0.6" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + url: "https://pub.dev" + source: hosted + version: "2.3.6" + device_info_plus: + dependency: transitive + description: + name: device_info_plus + sha256: eead12d1a1ed83d8283ab4c2f3fca23ac4082f29f25f29dff0f758f57d06ec91 + url: "https://pub.dev" + source: hosted + version: "10.1.0" + device_info_plus_platform_interface: + dependency: transitive + description: + name: device_info_plus_platform_interface + sha256: d3b01d5868b50ae571cd1dc6e502fc94d956b665756180f7b16ead09e836fd64 + url: "https://pub.dev" + source: hosted + version: "7.0.0" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492" + url: "https://pub.dev" + source: hosted + version: "0.9.2+1" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: b15c3da8bd4908b9918111fa486903f5808e388b8d1c559949f584725a6594d6 + url: "https://pub.dev" + source: hosted + version: "0.9.3+3" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" + source: hosted + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0 + url: "https://pub.dev" + source: hosted + version: "0.9.3+1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_compass: + dependency: "direct main" + description: + name: flutter_compass + sha256: be642484f9f6975c1c6edff568281b001f2f1e604de27ecea18d97eebbdef22f + url: "https://pub.dev" + source: hosted + version: "0.8.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 + url: "https://pub.dev" + source: hosted + version: "3.0.1" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da + url: "https://pub.dev" + source: hosted + version: "2.0.17" + flutter_speed_dial: + dependency: "direct main" + description: + name: flutter_speed_dial + sha256: "41d7ad0bc224248637b3a5e0b9083e912a75445bdb450cf82b8ed06d7af7c61d" + url: "https://pub.dev" + source: hosted + version: "6.2.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_tts: + dependency: "direct main" + description: + name: flutter_tts + sha256: cbb3fd43b946e62398560235469e6113e4fe26c40eab1b7cb5e7c417503fb3a8 + url: "https://pub.dev" + source: hosted + version: "3.8.5" + flutter_vision: + dependency: "direct main" + description: + path: "C:\\Users\\User\\Desktop\\capstone-2024-23\\frontend\\flutter_vision-master" + relative: false + source: path + version: "1.1.4" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + geolocator: + dependency: "direct main" + description: + name: geolocator + sha256: "5c496b46e245d006760e643cedde7c9fa785a34391b5eca857a46358f9bde02b" + url: "https://pub.dev" + source: hosted + version: "8.2.1" + geolocator_android: + dependency: transitive + description: + name: geolocator_android + sha256: "3fa9215caf1e4463adbdf1f21b07fdcb9bc2af2ef1df3715a52376b87bebb087" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + sha256: "2f2d4ee16c4df269e93c0e382be075cc01d5db6703c3196e4af20a634fe49ef4" + url: "https://pub.dev" + source: hosted + version: "2.3.6" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + sha256: "009a21c4bc2761e58dccf07c24f219adaebe0ff707abdfd40b0a763d4003fab9" + url: "https://pub.dev" + source: hosted + version: "4.2.2" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + sha256: "102e7da05b48ca6bf0a5bda0010f886b171d1a08059f01bfe02addd0175ebece" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + geolocator_windows: + dependency: transitive + description: + name: geolocator_windows + sha256: "4f4218f122a6978d0ad655fa3541eea74c67417440b09f0657238810d5af6bdc" + url: "https://pub.dev" + source: hosted + version: "0.1.3" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + google_maps: + dependency: transitive + description: + name: google_maps + sha256: "47eef3836b49bb030d5cb3afc60b8451408bf34cf753e571b645d6529eb4251a" + url: "https://pub.dev" + source: hosted + version: "7.1.0" + google_maps_flutter: + dependency: "direct main" + description: + name: google_maps_flutter + sha256: "982c2e22ec78d32701bfbd351311e8579a4952035381ac66462c0af11003107b" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + google_maps_flutter_android: + dependency: transitive + description: + name: google_maps_flutter_android + sha256: "256b3c974e415bd17555ceff76a5d0badd2cbfd29febfc23070993358f639550" + url: "https://pub.dev" + source: hosted + version: "2.7.0" + google_maps_flutter_ios: + dependency: transitive + description: + name: google_maps_flutter_ios + sha256: "6c50bce26ff73079b4401de5bfe77e89d89138897b9dcc6bdfbc7ada842f2bc1" + url: "https://pub.dev" + source: hosted + version: "2.5.2" + google_maps_flutter_platform_interface: + dependency: transitive + description: + name: google_maps_flutter_platform_interface + sha256: "167af879da4d004cd58771f1469b91dcc3b9b0a2c5334cc6bf71fd41d4b35403" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + google_maps_flutter_web: + dependency: transitive + description: + name: google_maps_flutter_web + sha256: eef2488eae840bc4d2b7d5210e26707c64fc2947a9d6f83d83e13bd01509b07d + url: "https://pub.dev" + source: hosted + version: "0.5.6+1" + html: + dependency: transitive + description: + name: html + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" + http: + dependency: "direct main" + description: + name: http + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.dev" + source: hosted + version: "0.13.6" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + image: + dependency: "direct dev" + description: + name: image + sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6" + url: "https://pub.dev" + source: hosted + version: "3.3.0" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: b6951e25b795d053a6ba03af5f710069c99349de9341af95155d52665cb4607c + url: "https://pub.dev" + source: hosted + version: "0.8.9" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "8e75431a62b7feb4fd55cb4a5c6f0ac4564460ec5dc09f9c4a0d50a5ce7c4cb9" + url: "https://pub.dev" + source: hosted + version: "0.8.10" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "869fe8a64771b7afbc99fc433a5f7be2fea4d1cb3d7c11a48b6b579eb9c797f0" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: f4a6f62be96d6fd268f32a6bf8ef444cd8e3fff64d16923c6e6fe55e0c84a761 + url: "https://pub.dev" + source: hosted + version: "0.8.10" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80" + url: "https://pub.dev" + source: hosted + version: "2.10.0" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + js_wrapping: + dependency: transitive + description: + name: js_wrapping + sha256: e385980f7c76a8c1c9a560dfb623b890975841542471eade630b2871d243851c + url: "https://pub.dev" + source: hosted + version: "0.7.4" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + url: "https://pub.dev" + source: hosted + version: "0.8.0" + meta: + dependency: transitive + description: + name: meta + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + mime: + dependency: transitive + description: + name: mime + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + pedantic: + dependency: transitive + description: + name: pedantic + sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "4356882e9abf51aa0d56e8fb886e0d6162719f2310dd71f0b8fa7f34908b128d" + url: "https://pub.dev" + source: hosted + version: "8.3.0" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: "6760eb5ef34589224771010805bea6054ad28453906936f843a8cc4d3a55c4a4" + url: "https://pub.dev" + source: hosted + version: "3.12.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + pigeon: + dependency: transitive + description: + name: pigeon + sha256: be883401d09121c427ed9c5f6e96427787d93d335f55e5e2b0d780a0a22cd561 + url: "https://pub.dev" + source: hosted + version: "18.0.0" + platform: + dependency: transitive + description: + name: platform + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + url: "https://pub.dev" + source: hosted + version: "3.1.4" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" + url: "https://pub.dev" + source: hosted + version: "3.7.4" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + provider: + dependency: "direct main" + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + quiver: + dependency: transitive + description: + name: quiver + sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 + url: "https://pub.dev" + source: hosted + version: "3.2.1" + sanitize_html: + dependency: transitive + description: + name: sanitize_html + sha256: "12669c4a913688a26555323fb9cec373d8f9fbe091f2d01c40c723b33caa8989" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + speech_to_text: + dependency: "direct main" + description: + name: speech_to_text + sha256: "57fef1d41bdebe298e84842c89bb4ac91f31cdbec7830c8cb1fc6b91d03abd42" + url: "https://pub.dev" + source: hosted + version: "6.6.0" + speech_to_text_macos: + dependency: transitive + description: + name: speech_to_text_macos + sha256: e685750f7542fcaa087a5396ee471e727ec648bf681f4da83c84d086322173f6 + url: "https://pub.dev" + source: hosted + version: "1.1.0" + speech_to_text_platform_interface: + dependency: transitive + description: + name: speech_to_text_platform_interface + sha256: a0df1a907091ea09880077dc25aae02af9f79811264e6e97ddb08639b7f771c2 + url: "https://pub.dev" + source: hosted + version: "2.2.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test: + dependency: "direct main" + description: + name: test + sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f + url: "https://pub.dev" + source: hosted + version: "1.24.9" + test_api: + dependency: transitive + description: + name: test_api + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + url: "https://pub.dev" + source: hosted + version: "0.6.1" + test_core: + dependency: transitive + description: + name: test_core + sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a + url: "https://pub.dev" + source: hosted + version: "0.5.9" + tflite_flutter: + dependency: "direct dev" + description: + name: tflite_flutter + sha256: "88b203c6efd7f4269aa137ef31e760d53e6639e60cd17bb86602462f72d4176b" + url: "https://pub.dev" + source: hosted + version: "0.9.5" + tflite_flutter_helper: + dependency: "direct dev" + description: + name: tflite_flutter_helper + sha256: acda0ca6d9ff36051cd45d32e0f6e4979c9d37d5b599d1f1a2900c14c708ed55 + url: "https://pub.dev" + source: hosted + version: "0.2.1" + tmap_ui_sdk: + dependency: "direct main" + description: + path: "." + ref: "1.0.26" + resolved-ref: eda927f4e4380be79b153d37698c5daf9cbcb974 + url: "https://github.com/TmapSDK/TmapUI_FlutterSDK.git" + source: git + version: "1.0.26" + tuple: + dependency: transitive + description: + name: tuple + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" + source: hosted + version: "2.0.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vibration: + dependency: "direct main" + description: + name: vibration + sha256: "778ace40e84852e6cf6017cdbaf6790a837d73ff3dd50b27da9ac232a19de8fc" + url: "https://pub.dev" + source: hosted + version: "1.8.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.dev" + source: hosted + version: "13.0.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: "1d8e795e2a8b3730c41b8a98a2dff2e0fb57ae6f0764a1c46ec5915387d257b2" + url: "https://pub.dev" + source: hosted + version: "2.4.4" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + win32: + dependency: transitive + description: + name: win32 + sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c" + url: "https://pub.dev" + source: hosted + version: "4.1.4" + win32_registry: + dependency: transitive + description: + name: win32_registry + sha256: "1c52f994bdccb77103a6231ad4ea331a244dbcef5d1f37d8462f713143b0bfae" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + url: "https://pub.dev" + source: hosted + version: "1.0.4" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.19.0" diff --git a/frontend/pradtice/pubspec.yaml b/frontend/pradtice/pubspec.yaml new file mode 100644 index 0000000000..46175d0f52 --- /dev/null +++ b/frontend/pradtice/pubspec.yaml @@ -0,0 +1,131 @@ +name: pradtice +description: "A new Flutter project." +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: '>=3.3.0 <4.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + flutter_compass : ^0.8.0 + speech_to_text: ^6.3.0 + flutter_tts : ^3.6.0 + android_id : ^0.3.2 + + camera: ^0.9.8+1 + image_picker: ^0.8.6+3 + flutter_speed_dial: ^6.2.0 + vibration : ^1.7.3 + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.6 + permission_handler: ^8.3.0 + geolocator: ^8.1.1 + google_maps_flutter: ^2.5.3 + provider: ^6.0.3 + + # 로드 되어있는 flutter_vision-master 경로로 설정! + path: C:\Users\User\Desktop\capstone-2024-23\frontend\flutter_vision-master + + # tmap_ui_sdk: + # git: + # url: https://github.com/TmapSDK/TmapUI_FlutterSDK.git + # ref: 1.0.26 # version. git tag name + + + http: ^0.13.4 + test: ^1.24.9 + + +dev_dependencies: + flutter_test: + sdk: flutter + + # camera: + # git: + # url: https://github.com/flutter/plugins + # path: packages/camera/camera + # ref: 9e46048ad2e1f085c1e8f6c77391fa52025e681f + + tflite_flutter: ^0.9.1 + tflite_flutter_helper: ^0.2.1 + image: ^3.3.0 + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^3.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + assets: + - assets/ + - assets/labels.txt + - assets/yolov5n.tflite + - assets/tessdata/ + - assets/eye_u.png + - assets/eye_u_mono.png + # - assets/best-fp16.tflite # 이후 객체 인식 커스터마이징 사용시에 사용 + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/frontend/pradtice/test/widget_test.dart b/frontend/pradtice/test/widget_test.dart new file mode 100644 index 0000000000..5d16f3e4e6 --- /dev/null +++ b/frontend/pradtice/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:pradtice/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget( MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/frontend/pradtice/web/favicon.png b/frontend/pradtice/web/favicon.png new file mode 100644 index 0000000000..8aaa46ac1a Binary files /dev/null and b/frontend/pradtice/web/favicon.png differ diff --git a/frontend/pradtice/web/icons/Icon-192.png b/frontend/pradtice/web/icons/Icon-192.png new file mode 100644 index 0000000000..b749bfef07 Binary files /dev/null and b/frontend/pradtice/web/icons/Icon-192.png differ diff --git a/frontend/pradtice/web/icons/Icon-512.png b/frontend/pradtice/web/icons/Icon-512.png new file mode 100644 index 0000000000..88cfd48dff Binary files /dev/null and b/frontend/pradtice/web/icons/Icon-512.png differ diff --git a/frontend/pradtice/web/icons/Icon-maskable-192.png b/frontend/pradtice/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000000..eb9b4d76e5 Binary files /dev/null and b/frontend/pradtice/web/icons/Icon-maskable-192.png differ diff --git a/frontend/pradtice/web/icons/Icon-maskable-512.png b/frontend/pradtice/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000000..d69c56691f Binary files /dev/null and b/frontend/pradtice/web/icons/Icon-maskable-512.png differ diff --git a/frontend/pradtice/web/index.html b/frontend/pradtice/web/index.html new file mode 100644 index 0000000000..faaddc7b9f --- /dev/null +++ b/frontend/pradtice/web/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + pradtice + + + + + + + + + + diff --git a/frontend/pradtice/web/manifest.json b/frontend/pradtice/web/manifest.json new file mode 100644 index 0000000000..7a991464ed --- /dev/null +++ b/frontend/pradtice/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "pradtice", + "short_name": "pradtice", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/frontend/pradtice/windows/.gitignore b/frontend/pradtice/windows/.gitignore new file mode 100644 index 0000000000..d492d0d98c --- /dev/null +++ b/frontend/pradtice/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/frontend/pradtice/windows/CMakeLists.txt b/frontend/pradtice/windows/CMakeLists.txt new file mode 100644 index 0000000000..b72d015bcf --- /dev/null +++ b/frontend/pradtice/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(pradtice LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "pradtice") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/frontend/pradtice/windows/flutter/CMakeLists.txt b/frontend/pradtice/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000000..903f4899d6 --- /dev/null +++ b/frontend/pradtice/windows/flutter/CMakeLists.txt @@ -0,0 +1,109 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/frontend/pradtice/windows/flutter/generated_plugin_registrant.cc b/frontend/pradtice/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000000..4968886dd2 --- /dev/null +++ b/frontend/pradtice/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,20 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); + FlutterTtsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterTtsPlugin")); + GeolocatorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("GeolocatorWindows")); +} diff --git a/frontend/pradtice/windows/flutter/generated_plugin_registrant.h b/frontend/pradtice/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000000..dc139d85a9 --- /dev/null +++ b/frontend/pradtice/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/frontend/pradtice/windows/flutter/generated_plugins.cmake b/frontend/pradtice/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000000..3e49529572 --- /dev/null +++ b/frontend/pradtice/windows/flutter/generated_plugins.cmake @@ -0,0 +1,26 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + file_selector_windows + flutter_tts + geolocator_windows +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/frontend/pradtice/windows/runner/CMakeLists.txt b/frontend/pradtice/windows/runner/CMakeLists.txt new file mode 100644 index 0000000000..394917c053 --- /dev/null +++ b/frontend/pradtice/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/frontend/pradtice/windows/runner/Runner.rc b/frontend/pradtice/windows/runner/Runner.rc new file mode 100644 index 0000000000..fe27e475f9 --- /dev/null +++ b/frontend/pradtice/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "pradtice" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "pradtice" "\0" + VALUE "LegalCopyright", "Copyright (C) 2024 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "pradtice.exe" "\0" + VALUE "ProductName", "pradtice" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/frontend/pradtice/windows/runner/flutter_window.cpp b/frontend/pradtice/windows/runner/flutter_window.cpp new file mode 100644 index 0000000000..955ee3038f --- /dev/null +++ b/frontend/pradtice/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/frontend/pradtice/windows/runner/flutter_window.h b/frontend/pradtice/windows/runner/flutter_window.h new file mode 100644 index 0000000000..6da0652f05 --- /dev/null +++ b/frontend/pradtice/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/frontend/pradtice/windows/runner/main.cpp b/frontend/pradtice/windows/runner/main.cpp new file mode 100644 index 0000000000..e7c10cb869 --- /dev/null +++ b/frontend/pradtice/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"pradtice", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/frontend/pradtice/windows/runner/resource.h b/frontend/pradtice/windows/runner/resource.h new file mode 100644 index 0000000000..66a65d1e4a --- /dev/null +++ b/frontend/pradtice/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/frontend/pradtice/windows/runner/resources/app_icon.ico b/frontend/pradtice/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000000..c04e20caf6 Binary files /dev/null and b/frontend/pradtice/windows/runner/resources/app_icon.ico differ diff --git a/frontend/pradtice/windows/runner/runner.exe.manifest b/frontend/pradtice/windows/runner/runner.exe.manifest new file mode 100644 index 0000000000..a42ea7687c --- /dev/null +++ b/frontend/pradtice/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/frontend/pradtice/windows/runner/utils.cpp b/frontend/pradtice/windows/runner/utils.cpp new file mode 100644 index 0000000000..b2b08734db --- /dev/null +++ b/frontend/pradtice/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length <= 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/frontend/pradtice/windows/runner/utils.h b/frontend/pradtice/windows/runner/utils.h new file mode 100644 index 0000000000..3879d54755 --- /dev/null +++ b/frontend/pradtice/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/frontend/pradtice/windows/runner/win32_window.cpp b/frontend/pradtice/windows/runner/win32_window.cpp new file mode 100644 index 0000000000..60608d0fe5 --- /dev/null +++ b/frontend/pradtice/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/frontend/pradtice/windows/runner/win32_window.h b/frontend/pradtice/windows/runner/win32_window.h new file mode 100644 index 0000000000..e901dde684 --- /dev/null +++ b/frontend/pradtice/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/index.md b/index.md index b1e80ac9bb..ed00367626 100644 --- a/index.md +++ b/index.md @@ -1,37 +1,342 @@ -## Welcome to GitHub Pages +### [EYE-U](https://kookmin-sw.github.io/capstone-2024-23) 객체탐지를 활용한 시각장애인용 보행 보조 앱
-You can use the [editor on GitHub](https://github.com/kookmin-sw/cap-template/edit/master/index.md) to maintain and preview the content for your website in Markdown files. +
-Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files. +## 📌 프로젝트 개요 | Project Abstract +**“혹시 흰 지팡이나 안내견에 의지하여 길을 걷는 시각장애인을 본 적 있나요?"**

+기존의 시각장애인을 위한 길 안내는 주로 점자판이나 안내견과 같은 수단을 사용해왔습니다.
+하지만 이러한 방법들은 여러 제약과 불편한 점이 있습니다.
+이 문제를 극복하기 위해 저희 EYE-U는 시각 장애가 있는 분들을 위한 내비게이션 앱을 개발하고자 합니다.

+본 프로젝트는 시각장애인 또는 저시력자분들을 주요 대상으로 하여, 그들이 일상 생활에서 겪는 보행의 불편함과 위험을 줄여주는 보행 보조 앱입니다.
+저희 앱은 실시간 음성 길 안내, 장애물 탐지, 위험물 알림 기능을 통해 이용자가 보다 안전하고 편리한 서비스를 경험할 수 있도록 도와줍니다.
-### Markdown +
-Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for +**“Have you ever seen a visually impaired person walking down the street relying on a white cane or guide dog?"** +

+Existing route guidance for the visually impaired has mainly used means such as Braille boards or guide dogs. However, these methods have several limitations and inconveniences. To overcome this problem, we at EYE-U want to develop a navigation app for people with visual impairments. -```markdown -Syntax highlighted code block +This project is a walking assistance app targeting people who are visually impaired or have low vision and reduces the discomfort and risk of walking they experience in their daily lives. Our app helps users experience a safer and more convenient service through real-time voice directions, obstacle detection, and dangerous goods notification functions. +


-# Header 1 -## Header 2 -### Header 3 +## 📃 포스터 | Poster +image -- Bulleted -- List +

-1. Numbered -2. List -**Bold** and _Italic_ and `Code` text +## 📘 주요 기능 | Key Features +- 탐지 모드 + - 장애물 및 위험물 탐지, 진동 경고 +- 보행 모드 + - 실시간 내비게이션 길 음성 안내 + 위험물 탐지 +

+ +## 💡 EYE-U POINT +- UI/UX + - 타겟 맞춤형 UI/UX + +- 보행자 친화 길안내 + - 목적지 출입구 및 보행로를 우선 + +- voice-all-in-one + - 불필요한 서비스 과정 제거 + - VOICE만을 이용해서 모든 기능 이용 가능 + +- 위험 물체 감지 + - 실시간 위험물 감지 및 진동 경고 +
-[Link](url) and ![Image](src) -``` -For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/). +
-### Jekyll Themes +## 📁 서비스 프로세스 | Sevice Process +image +
+
-Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/kookmin-sw/cap-template/settings). The name of this theme is saved in the Jekyll `_config.yml` configuration file. +## 🎞 소개 영상 | Introduction video +[![소개영상](https://github.com/kookmin-sw/capstone-2024-23/assets/143046108/fbbb76cf-4f32-4450-8ba2-bba2e690552a)](https://www.youtube.com/watch?v=sgO9tWCrPbo) +
+
+## 🎞 시연 영상 | Demonstration video +[![시연영상](https://github.com/kookmin-sw/capstone-2024-23/assets/143046108/23c35d4a-64ef-480c-b2cc-998f91cf2b7a)](https://www.youtube.com/watch?v=FsVF8S9SSMI) +
+
+
-### Support or Contact +## 📃 매뉴얼 | Manual + + 매뉴얼 + +

-Having trouble with Pages? Check out our [documentation](https://help.github.com/categories/github-pages-basics/) or [contact support](https://github.com/contact) and we’ll help you sort it out. +## 팀 소개 +#### 김호준 +김호준
+ +~~~ +Student ID : ****5206 +role : AI, 객체 인식 +E-mail: hojuni9999@kookmin.ac.kr +~~~ + +#### 박성원 +박성원
+ +~~~ +Student ID : ****5207 +role : Front-end, 지도 +E-mail: tjddnjs612@kookmin.ac.kr +~~~ + +#### 윤미나 +윤미나
+ +~~~ +Student ID : ****5209 +role : Back-end, 데이터베이스 관리 +E-mail: skwhjj@kookmin.ac.kr +~~~ + +#### 이태영 +이태영
+ +~~~ +Student ID : ****5211 +role : Front-end, TTS +E-mail: sam4886@kookmin.ac.kr +~~~ + +#### 정회창 +정회창
+ +~~~ +Student ID : ****5212 +role : Back-end, AWS 서버 관리 +E-mail: picetea44@kookmin.ac.kr +~~~ + +
+ +## ⤴ 배포 | Distribution +
+배포 +
+ +~~~ +- 어플리케이션 APK +1. Android Studio - build + +2. 해당 위치에 설치된 APK 파일을 배포한다. +capstone-2024-23\frontend\practice\build\app\outputs\flutter-apk +~~~ + +
+
+
+ +## 🔎 실행 방법 | Execution method + +
+실행 방법 +
+ +~~~ +1. git clone
+$ git clone https://github.com/kookmin-sw/capstone-2024-23.git + +2. Android Studio - build + +3. 해당 위치에 설치된 APK 파일 실행한다. +capstone-2024-23\frontend\practice\build\app\outputs\flutter-apk +~~~ + +
+
+ +
+ +## ⚙ 환경 설정 | Configuration Settings + +
+서버 실행 환경 설정 +
+ + +리눅스(우분투) 기준 +1. JAVA 설치 + +~~~ +# 1.apt update +$ sudo apt-get update + +# 2. java21 설치 +$ sudo apt-get install openjdk-21-jdk + +# 3. 설치 후 버젼 확인 +$ java -version +~~~ + +2. 환경변수 설정 + +~~~ +# 환경변수 확인 (아무것도 안떠야 정상) +$ echo $JAVA_HOME + +# Java 절대 경로 확인 +$ which java +$ readlink -f "which java에서 나온 경로 기입" +# 절대 경로 shift + ctrl + c로 복사해두기 + +# 환경변수 설정 진입 (초기화 방지) +$ vi /etc/profile + +# 파일 최하단에 아래 문구 삽입 +#JAVA_HOME에 아까 복사한 절대 경로 삽입 +export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 +export PATH=$PATH:$JAVA_HOME/bin +export CLASSPATH=$JAVA_HOME/jre/lib + +# 환경변수 재확인 (경로가 떠야 정상) +$ echo $JAVA_HOME +~~~ + +3. MySQL 설치 (원격 접속 설정 포함) + +~~~ +# mysql 설치 +$ apt-get install mysql-server + +# mysql 설치 확인 +$ mysql --version + +# mysql 실행(택1) +$ mysql -u root -p # root 사용자 접근시 +$ mysql -u yoon -p # 특정 계정으로 접근시 ex) yoon 계정 사용 + +# mysql root 비밀번호 설정 (설치 후 반드시 설정) +# 1. mysql 설정 들어가기 +mysql> use mysql + +# 2. root 비밀번호 설정 +mysql> alter user "root"@"localhost" identified with mysql_native_password by "암호"; + +# 3. 저장하기 +mysql> FLUSH PRIVILEGES; + +# 사용자 계정 생성하기 +# 1. mysql 설정 들어가기 +mysql> use mysql + +# 2. 외부 접근을 허용하는 사용자 추가하기(원격으로 mysql접근가능) +create user '계정명'@'%' identified by '0000'; + +# 3. 권한 부여해주기 +grant all privileges on *.* to '계정명'@'%'; + +# 4. 저장하기 +mysql> FLUSH PRIVILEGES; + +# 외부 접속 허용하기 +# 1. 최고 권한 부여 +$ sudo su + +# 2. 경로 이동하기 +$ cd/etc/mysql/mysql.conf.d + +# 3. 편집기 실행 +$ vi mysqld.cnf + +# 4. bind-address 수정하기 (i 눌러 수정모드 진입, 수정 후 ESC 누르고 :wq 를 통해 저장 후 종료) +bind-address = 0.0.0.0 + +# 5. 서버 재시작 +service mysql restart +~~~ + +4. git clone + +~~~ +$ git clone https://github.com/kookmin-sw/capstone-2024-23.git +~~~ + +5. Build & Upload + +~~~ +1. Intellij bootJar 이용하여 빌드 +2. FileZilla 업로드 +호스트에 자신이 만든 EC2 IP 주소 입력하고, 키 파일에 EC2 생성시 받은 PEM 키 넣어주기 +~~~ + +6. 서버 실행 + +~~~ +ssh -i ~/capstone2024Key.pem ubuntu@EC2 IP 주소 + +nohup java -jar 자바파일이름.jar & + +#prod 버젼으로 실행 +nohup java -jar -Dspring.profiles.active=prod 자바파일이름.jar & + +#config 별도 폴더 말고 외부의 application.properties 사용하기 +java -Dspring.config.location=classpath:/application.properties -jar yourapp.jar +~~~ +
+
+ +
+클라이언트 실행 환경설정 +
+ +1. 안드로이드스튜디오 Download (sdk 29 이상) +2. 플러터 3.19 버전 Download +3. git clone +$ git clone https://github.com/kookmin-sw/capstone-2024-23.git +4. frontend/pradtice/pubspec.yaml -> flutter_vision-master 경로 설정 (본인 경로) + +~~~ + path: /Users/yoon/StudioProjects/capstone-2024-23/frontend/flutter_vision-master +~~~ + +5. pubspec.yaml -> Pub.get Download + + +
+
+ +
+안드로이드 실행 환경설정 +
+ +1. usb 휴대폰 연결 +2. 설정 -> 화면 7번 터치 -> 개발자모드 실행 +3. 앱 실행 + +
+
+

+ + +## 🗂 문서 | Document + + +
+ + 중간발표 자료 + + | + + 최종발표 자료 + + | + 사용자 매뉴얼 + + | + 포스터 + +
diff --git "a/\353\260\234\355\221\234\354\236\220\353\243\214/.DS_Store" "b/\353\260\234\355\221\234\354\236\220\353\243\214/.DS_Store" new file mode 100644 index 0000000000..be9c112d61 Binary files /dev/null and "b/\353\260\234\355\221\234\354\236\220\353\243\214/.DS_Store" differ diff --git "a/\353\260\234\355\221\234\354\236\220\353\243\214/EYE-U \354\265\234\354\242\205\353\260\234\355\221\234.pdf" "b/\353\260\234\355\221\234\354\236\220\353\243\214/EYE-U \354\265\234\354\242\205\353\260\234\355\221\234.pdf" new file mode 100644 index 0000000000..78b12044aa Binary files /dev/null and "b/\353\260\234\355\221\234\354\236\220\353\243\214/EYE-U \354\265\234\354\242\205\353\260\234\355\221\234.pdf" differ diff --git "a/\353\260\234\355\221\234\354\236\220\353\243\214/EYE-U.pptx" "b/\353\260\234\355\221\234\354\236\220\353\243\214/EYE-U.pptx" new file mode 100644 index 0000000000..0cebc12171 Binary files /dev/null and "b/\353\260\234\355\221\234\354\236\220\353\243\214/EYE-U.pptx" differ