Feat: 사용자 설정 기능 구현 (포트, 루트 디렉토리)
- FTPConfig 클래스 생성: SharedPreferences 기반 설정 관리 * 포트 번호 저장/로드 * 루트 디렉토리 URI 및 경로 저장/로드 - MainActivity UI 업데이트 * ScrollView로 전체 레이아웃 감싸기 * 설정 섹션 추가 (포트 입력, 디렉토리 선택) * Storage Access Framework로 디렉토리 선택 기능 * 설정 유효성 검사 (포트 범위: 1024-65535) - MainActivity 로직 업데이트 * ActivityResultLauncher로 디렉토리 선택 * takePersistableUriPermission으로 지속적 권한 획득 * 설정 로드 및 저장 기능 * 서버 시작 전 루트 디렉토리 필수 체크 - FTPService 수정 * Intent로 포트 및 루트 디렉토리 전달받음 * FTPServer에 설정값 전달 - FTPServer 생성자 확장 * 포트 및 루트 디렉토리 파라미터 추가 * FTPSession에 설정값 전달 - FTPSession 생성자 확장 * 루트 디렉토리 파라미터 추가 * FTPFileSystem에 전달 - FTPFileSystem 생성자 확장 * 사용자 지정 루트 디렉토리 지원 * null일 경우 기본 디렉토리 사용 * 경로 유효성 검증 이제 사용자가 원하는 디렉토리를 FTP 루트로 설정 가능 Android 11+ Scoped Storage 문제 해결 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="16dp"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/titleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -64,4 +68,92 @@
|
||||
app:layout_constraintTop_toBottomOf="@id/startButton"
|
||||
android:layout_marginTop="16dp" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="#CCCCCC"
|
||||
android:layout_marginTop="32dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/stopButton"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/settingsTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Settings"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginTop="24dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/divider"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/portLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Port:"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginTop="24dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/settingsTitle"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/portEditText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="number"
|
||||
android:hint="2121"
|
||||
android:layout_marginStart="16dp"
|
||||
app:layout_constraintBaseline_toBaselineOf="@id/portLabel"
|
||||
app:layout_constraintStart_toEndOf="@id/portLabel"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/rootDirLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Root Directory:"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginTop="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/portLabel"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/rootDirPathTextView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Not selected"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:padding="8dp"
|
||||
android:background="@android:color/darker_gray"
|
||||
android:ellipsize="start"
|
||||
android:singleLine="true"
|
||||
app:layout_constraintTop_toBottomOf="@id/rootDirLabel"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/selectDirButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Select Directory"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/rootDirPathTextView"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/saveSettingsButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Save Settings"
|
||||
android:minWidth="150dp"
|
||||
android:layout_marginTop="24dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/selectDirButton"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
||||
Reference in New Issue
Block a user