Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
Escaper-Park committed Apr 27, 2024
2 parents e0583f4 + 46d9bee commit 15b92b7
Show file tree
Hide file tree
Showing 27 changed files with 610 additions and 578 deletions.
24 changes: 10 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@
![홈즐겨찾기](./images/01.png)
![카테고리](./images/03.png)
![카테고리라이브](./images/04.png)
![동영상다시보기](./images/02.png)
![라이브탐색](./images/05.png)

## 업데이트
### v0.2.3
- 화질 개선을 위해 Low Latency HLS에서 HLS로 변경
- 홈 화면 팔로우, 인기 채널 불러오기 에러 수정
- VOD 시간 탐색시 키 누르고 있으면 계속 이동

### v0.2.2
- 채널 동영상에서 연령 인증 동영상이 재생되지 않는 현상 수정
- gif 이모티콘 성능 최적화, 채팅이 가끔 나오지 않는 현상 수정
Expand All @@ -23,7 +26,6 @@

## 패치노트 - v0.2
### 1. 카테고리 검색, 라이브, 동영상, 홈 화면 즐겨찾기(로컬)
- 홈 화면 즐겨찾기는 로컬 데이터로 저장되기 때문에 캐시를 삭제하면 초기화됩니다.
### 2. 동영상 전체 다시보기 추가
### 3. 채팅창 이모티콘 대응
### 4. 라이브 시청 중 탐색 기능(인기, 팔로우, 카테고리) 추가
Expand Down Expand Up @@ -62,11 +64,10 @@ APK 파일을 다운받아서 수동으로 설치합니다.
```

## 다운로드
[**APK 파일 다운로드 (v0.2.2)**](https://github.com/Escaper-Park/unofficial_chzzk_android_tv/releases/tag/v0.2.2)
[**APK 파일 다운로드 (v0.2.2)**](https://github.com/Escaper-Park/unofficial_chzzk_android_tv/releases/tag/v0.2.3)

### 설치 파일
- 사용하시는 CPU 타입에 따라 설치하시면 됩니다.
- 가능한 최적화 버전(v8a, v7a, x86)으로 설치해주세요. (설치 불가시 통합버전으로 설치)
- 대부분 v7a로 설치 가능. 설치 불가시 통합버전 또는 사용하시는 CPU 타입에 따라 설치하시면 됩니다. (가능한 v7a로 설치)

## 현재 사용 가능한 기능
- 로그인 (Headless WebView 또는 WebView)
Expand All @@ -85,11 +86,6 @@ APK 파일을 다운받아서 수동으로 설치합니다.
그 외 기능은 로그인하지 않아도 작동합니다.

## 로그인
- 로그인은 정식 출시된 어플이 아니므로 부득이하게 [Headless WebView]를 사용했습니다. (쿠키 사용)
- 계정에 2단계 인증이 걸려있다면 로그인 버튼 클릭 후 모바일 알림을 확인해주세요.

## Future Works
- 화질 설정 (멀티뷰 성능 이슈)
- 멀티뷰 최적화
- 팔로우 추가/제거
- 삼성TV (Tizen OS) 지원 (오래걸림)
로그인은 정식 출시된 어플이 아니므로 부득이하게 [Headless WebView]를 사용했습니다. (쿠키 사용)

계정에 2단계 인증이 걸려있다면 로그인 버튼 클릭 후 모바일 알림을 확인해주세요
12 changes: 7 additions & 5 deletions lib/src/common/constants/api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class APIUrl {

static String user() => '$_naverGameUrl/v1/user/getUserStatus';

static String following({int size = 10, int page = 0}) =>
static String following({int size = 505, int page = 0}) =>
'$_chzzkAPIUrl/service/v1/channels/followings?size=$size&page=$page';

static String followingLiveChannels() =>
Expand Down Expand Up @@ -85,11 +85,12 @@ class APIUrl {
required String categoryId,
required int? concurrentUserCount,
required int? liveId,
int size = 18,
}) {
if (concurrentUserCount == null || liveId == null) {
return '$_chzzkAPIUrl/service/v2/categories/$categoryType/$categoryId/lives?';
return '$_chzzkAPIUrl/service/v2/categories/$categoryType/$categoryId/lives?size=$size';
} else {
return '$_chzzkAPIUrl/service/v2/categories/$categoryType/$categoryId/lives?concurrentUserCount=$concurrentUserCount&liveId=$liveId';
return '$_chzzkAPIUrl/service/v2/categories/$categoryType/$categoryId/lives?size=$size&concurrentUserCount=$concurrentUserCount&liveId=$liveId';
}
}

Expand All @@ -98,11 +99,12 @@ class APIUrl {
required String categoryId,
required int? publishDateAt,
required int? readCount,
int size = 18,
}) {
if (publishDateAt == null || readCount == null) {
return '$_chzzkAPIUrl/service/v2/categories/$categoryType/$categoryId/videos?';
return '$_chzzkAPIUrl/service/v2/categories/$categoryType/$categoryId/videos?size=$size';
} else {
return '$_chzzkAPIUrl/service/v2/categories/$categoryType/$categoryId/videos?publishDateAt=$publishDateAt&readCount=$readCount';
return '$_chzzkAPIUrl/service/v2/categories/$categoryType/$categoryId/videos?size=$size&publishDateAt=$publishDateAt&readCount=$readCount';
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/src/common/constants/app_version.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
class AppVersion {
static const String version = 'v0.2.2';
static const String version = 'v0.2.3';
}
1 change: 0 additions & 1 deletion lib/src/common/widgets/base_scaffold.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ class BaseScaffold extends ConsumerWidget {
/// screen overflow error.
final bool useTextField;

///
final AppBar? appBar;

@override
Expand Down
14 changes: 11 additions & 3 deletions lib/src/common/widgets/circle_avatar_profile_image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,17 @@ class CircleAvatarProfileImage extends StatelessWidget {
backgroundColor: Colors.black54,
)
: profileImageUrl!.contains('.gif')
? CircleAvatar(
radius: radius,
backgroundColor: Colors.black54,
? Container(
width: radius * 2,
height: radius * 2,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color:
hasBorder ? AppColors.chzzkColor : Colors.transparent,
width: 2.0,
),
),
)
: OptimizedCachedNetworkImage(
imageUrl: profileImageUrl!,
Expand Down
2 changes: 1 addition & 1 deletion lib/src/common/widgets/optimized_image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class OptimizedCachedNetworkImage extends StatelessWidget {
key: UniqueKey(),
imageUrl: imageUrl,
imageBuilder: imageBuilder,
maxWidthDiskCache: cacheSize,
// maxWidthDiskCache: cacheSize
memCacheWidth: cacheSize,
placeholder: (context, url) => SizedBox(
width: imageWidth,
Expand Down
151 changes: 151 additions & 0 deletions lib/src/features/category/controller/category_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import 'package:shared_preferences/shared_preferences.dart';

import '../../../utils/shared_preferences/shared_prefs.dart';
import '../../auth/controller/auth_controller.dart';
import '../../live/model/live.dart';
import '../../live/repository/live_repository.dart';
import '../../vod/model/vod.dart';
import '../../vod/repository/vod_repository.dart';
import '../model/category.dart';
import '../repository/category_repository.dart';

Expand Down Expand Up @@ -118,3 +122,150 @@ class CurrentCategoryItem extends _$CurrentCategoryItem {
if (state != item) state = item;
}
}

@riverpod
class CategoryLiveController extends _$CategoryLiveController {
Options? _options;
LivePage? _next;

@override
FutureOr<List<LiveDetail>?> build({required Category category}) async {
final auth = await ref.read(authControllerProvider.future);

_options = auth?.getOptions();

return await _initFetch();
}

Future<List<LiveDetail>?> _initFetch() async {
final LiveResponse? liveResponse =
await ref.watch(categoryRepositoryProvider).getCategoryLiveResponses(
category: category,
next: _next,
options: _options,
);

_next = liveResponse?.page;

return liveResponse?.liveDetails ?? [];
}

Future<void> fetchMore() async {
if (_next != null) {
final prev = state.value;

// Show Loading State in Category Lives Page
ref.read(categoryLoadingStateProvider.notifier).setState(true);

state = await AsyncValue.guard(() async {
final response = await ref
.watch(categoryRepositoryProvider)
.getCategoryLiveResponses(
category: category,
next: _next,
options: _options,
);

_next = response?.page;

if (response?.liveDetails == null || _next == null) {
// Show Loading State in Category Lives Page
ref.read(categoryLoadingStateProvider.notifier).setState(false);

return [...prev!];
}

ref.read(categoryLoadingStateProvider.notifier).setState(false);
return [...prev!, ...response!.liveDetails!];
});
}
}

Future<LiveDetail?> getLiveDetail(final String channelId) async {
try {
return await ref.watch(liveRepositoryProvider).getLiveDetail(
channelId: channelId,
options: _options,
);
} catch (_) {
return null;
}
}
}

@riverpod
class CategoryVodController extends _$CategoryVodController {
Options? _options;
VodPage? _next;

@override
FutureOr<List<Vod>?> build({required Category category}) async {
final auth = await ref.read(authControllerProvider.future);

_options = auth?.getOptions();

return await _initFetch();
}

Future<List<Vod>?> _initFetch() async {
final VodResponse? vodResponse =
await ref.watch(categoryRepositoryProvider).getCategoryVodResponse(
category: category,
next: _next,
options: _options,
);

_next = vodResponse?.page;

return vodResponse?.vods ?? [];
}

Future<void> fetchMore() async {
if (_next != null) {
final prev = state.value;

// Show Loading State in Category Vods Page
ref.read(categoryLoadingStateProvider.notifier).setState(true);

state = await AsyncValue.guard(() async {
final response =
await ref.watch(categoryRepositoryProvider).getCategoryVodResponse(
category: category,
next: _next,
options: _options,
);

_next = response?.page;

if (response?.vods == null || _next == null) {
// Show Loading State in Category Vods Page
ref.read(categoryLoadingStateProvider.notifier).setState(false);

return [...prev!];
}

ref.read(categoryLoadingStateProvider.notifier).setState(false);
return [...prev!, ...response!.vods!];
});
}
}

Future<String?> getVodPath({required int videoNo}) async {
return await ref.watch(vodRepositoryProvider).getVodPath(
videoNo: videoNo,
options: _options,
);
}
}

@riverpod
class CategoryLoadingState extends _$CategoryLoadingState {
@override
bool build() {
return false;
}

void setState(bool value) {
state = value;
}
}
Loading

0 comments on commit 15b92b7

Please sign in to comment.