Merge branch 'feature/viewer-attachment' of bitbucket.org:equilibriumito/gabinete-digital-fo into feature/viewer-attachment

This commit is contained in:
Peter Maquiran
2024-04-11 09:14:48 +01:00
9 changed files with 521 additions and 47 deletions
+33 -33
View File
@@ -1,36 +1,36 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest package="com.gpr.gabinetedigital" xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:requestLegacyExternalStorage="true" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" android:usesCleartextTraffic="true">
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode" android:exported="true" android:label="@string/title_activity_main" android:launchMode="singleTop" android:name=".MainActivity" android:theme="@style/AppTheme.NoActionBarLaunch">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:exported="true" android:label="@string/app_name" android:name="de.mindlib.sendIntent.SendIntentActivity" android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
<data android:mimeType="video/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
<data android:mimeType="video/*" />
</intent-filter>
</activity>
<provider android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true" android:name="androidx.core.content.FileProvider">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
</provider>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:requestLegacyExternalStorage="true" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" android:usesCleartextTraffic="true">
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode" android:exported="true" android:label="@string/title_activity_main" android:launchMode="singleTop" android:name=".MainActivity" android:theme="@style/AppTheme.NoActionBarLaunch">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:exported="true" android:label="@string/app_name" android:name="de.mindlib.sendIntent.SendIntentActivity" android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
<data android:mimeType="video/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
<data android:mimeType="video/*" />
</intent-filter>
</activity>
<provider android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true" android:name="androidx.core.content.FileProvider">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>
@@ -10,7 +10,7 @@ import { ViewPublicationsPage } from './view-publications.page';
import { Attributes, IntersectionObserverHooks, LazyLoadImageModule, LAZYLOAD_IMAGE_HOOKS } from 'ng-lazyload-image';
import { ShowMorePageModule } from 'src/app/shared/publication/view-publications/show-more/show-more.module'
import { VisibilityDirective } from 'src/app/services/directives/visibility1.directive';
import { SwiperPageModule } from 'src/app/shared/swiper/swiper.module';
export class LazyLoadImageHooks extends IntersectionObserverHooks {
setup(attributes: Attributes) {
attributes.offset = 10;
@@ -30,9 +30,10 @@ setup(attributes: Attributes) {
LazyLoadImageModule,
//page
ShowMorePageModule,
SwiperPageModule
],
exports: [ViewPublicationsPage],
declarations: [ViewPublicationsPage, VisibilityDirective],
declarations: [ViewPublicationsPage],
providers: [{provide: LAZYLOAD_IMAGE_HOOKS, useClass: LazyLoadImageHooks}],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
@@ -43,15 +43,24 @@
<ion-card *ngFor="let publication of publicationFolderService.publicationList[folderId] let i = index">
<ion-card-content>
<div style="width: 364px; height: 395px;">
<app-swiper
[publicationList]=publication
></app-swiper>
</div>
<swiper-container #swiper [modules]="swiperModules" [preloadImages]="false" [slidechange]="onSlideChange()">
<!-- <swiper-container #swipers [slidechange]="onSlideChange()">
<swiper-slide *ngFor="let files of publication.Files let k = index">
<div >
<img *ngIf="checkFileType.checkFileType(files.FileExtension ) == 'image'" class="post-img"
[lazyLoad]="'data:image/jpg;base64,' + files.FileBase64">
<video #videoElement [appVisibility]="onVisibilityChange" *ngIf="checkFileType.checkFileType(files.FileExtension ) == 'video'" class="post-video" controls="controls" preload="metadata"
<video #videoElement [appVisibility]="onVisibilityChange" *ngIf="checkFileType.checkFileType(files.FileExtension ) == 'video'" class="post-video" controls="controls" preload="none"
playsinline webkit-playsinline="webkit-playsinline" (play)="stopvideoService.registerVideoWithEvent($event)" (click)="preventVideoPlay($event)">
<source [src]="files.FileBase64" type="video/mp4" >
</video>
@@ -59,19 +68,19 @@
</div>
</swiper-slide>
</swiper-container>
</swiper-container> -->
<!-- <div *ngIf="publication.FileExtension == 'mp4'"
(click)="goToPublicationDetail(publication.DocumentId, publication.ProcessId)" class="post-video">
</div> -->
<div *ngIf="publication.Files.length > 2" class="dots-container">
<!-- <div *ngIf="publication.Files.length > 2" class="dots-container">
<span *ngFor="let files of publication.Files; let k = index"
[class.dotsSwiper]="true"
[class.active-dot]="swiperIndex === k"
(click)="goToSlide(k)">
</span>
</div>
</div> -->
<div (click)="goToPublicationDetail(publication.DocumentId, publication.ProcessId)" class="post-content" >
<div class="post-title-time">
@@ -56,6 +56,8 @@ export class ViewPublicationsPage implements OnInit {
};
swiperModules = [IonicSlides];
publicationList: any
@ViewChild('VideoManager') VideoManager;
@ViewChildren('videoElement') videoElements: QueryList<ElementRef>;
@ViewChild('swiper')
@@ -267,6 +269,7 @@ export class ViewPublicationsPage implements OnInit {
if (!found) {
this.publicationFolderService.publicationList[folderId].push(publicationDetails)
this.publicationFolderService.revertPublicationOrder(folderId)
this.publicationList = this.publicationFolderService.publicationList[folderId];
} else {
+52 -2
View File
@@ -1,4 +1,4 @@
import { NgModule } from '@angular/core';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
@@ -7,6 +7,17 @@ import { IonicModule } from '@ionic/angular';
import { SwiperPageRoutingModule } from './swiper-routing.module';
import { SwiperPage } from './swiper.page';
import { Attributes, IntersectionObserverHooks, LazyLoadImageModule, LAZYLOAD_IMAGE_HOOKS } from 'ng-lazyload-image';
import { VisibilityDirective } from 'src/app/services/directives/visibility1.directive';
export class LazyLoadImageHooks extends IntersectionObserverHooks {
setup(attributes: Attributes) {
attributes.offset = 10;
attributes.defaultImagePath = "/assets/icon/icon-no-image.svg";
attributes.errorImagePath = "/assets/icon/icon-no-image.svg";
return super.setup(attributes);
}
}
@NgModule({
imports: [
@@ -15,6 +26,45 @@ import { SwiperPage } from './swiper.page';
IonicModule,
SwiperPageRoutingModule
],
declarations: [SwiperPage]
declarations: [SwiperPage,VisibilityDirective],
exports:[SwiperPage],
providers: [{provide: LAZYLOAD_IMAGE_HOOKS, useClass: LazyLoadImageHooks}],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class SwiperPageModule {}
/*
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { SwiperPageRoutingModule } from './swiper-routing.module';
import { SwiperPage } from './swiper.page';
import { Attributes, IntersectionObserverHooks, LazyLoadImageModule, LAZYLOAD_IMAGE_HOOKS } from 'ng-lazyload-image';
import { VisibilityDirective } from 'src/app/services/directives/visibility1.directive';
export class LazyLoadImageHooks extends IntersectionObserverHooks {
setup(attributes: Attributes) {
attributes.offset = 10;
attributes.defaultImagePath = "/assets/icon/icon-no-image.svg";
attributes.errorImagePath = "/assets/icon/icon-no-image.svg";
return super.setup(attributes);
}
}
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
SwiperPageRoutingModule
],
declarations: [SwiperPage,VisibilityDirective],
providers: [{provide: LAZYLOAD_IMAGE_HOOKS, useClass: LazyLoadImageHooks}],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class SwiperPageModule {} */
+29 -2
View File
@@ -1,9 +1,36 @@
<ion-header>
<!-- <ion-header>
<ion-toolbar>
<ion-title>swiper</ion-title>
</ion-toolbar>
</ion-header>
</ion-header> -->
<ion-content>
<swiper-container #swipers [slidechange]="onSlideChange()">
<swiper-slide *ngFor="let files of publicationList.Files let k = index">
<div >
<img *ngIf="checkFileType.checkFileType(files.FileExtension ) == 'image'" class="post-img"
[src]="'data:image/jpg;base64,' + files.FileBase64">
<video #videoElement [appVisibility]="onVisibilityChange" *ngIf="checkFileType.checkFileType(files.FileExtension ) == 'video'" class="post-video" controls="controls" preload="none"
playsinline webkit-playsinline="webkit-playsinline" (play)="stopvideoService.registerVideoWithEvent($event)">
<source [src]="files.FileBase64" type="video/mp4" >
</video>
</div>
</swiper-slide>
</swiper-container>
</ion-content>
<ion-footer>
<div *ngIf="publicationList.Files.length > 2" class="dots-container">
<span *ngFor="let files of publicationList.Files; let k = index"
[class.dotsSwiper]="true"
[class.active-dot]="swiperIndex === k"
(click)="goToSlide(k)"
>
</span>
</div>
</ion-footer>
+325
View File
@@ -0,0 +1,325 @@
@import "~src/function.scss";
:host {
background: transparent;
padding: 0 !important;
}
ion-content {
--background: transparent;
--border-radius: 30px;
}
ion-toolbar {
--border-width: 0 !important;
--border-style: none;
--padding-top: 0px !important;
--padding-start: 0px !important;
--padding-right: 0px !important;
--padding-end: 0px !important;
}
.div-top-header {
width: 400px;
margin: 0 auto;
background-color: #0782c9;
padding-top: 15px;
border: 0 !important;
}
.div-search {
font-size: rem(45);
float: left;
margin: 0 0 0 10px;
}
.div-logo {
background: transparent;
width: 140px;
margin: 5px 0 0px 71px;
float: left;
}
.div-logo img {
width: 100%;
}
.div-profile {
font-size: rem(45);
float: right;
margin-right: 10px;
}
.main-header {
width: 100%; /* 400px */
height: 100%;
font-family: Roboto;
background-color: #fff;
overflow: hidden;
padding: 25px 20px 0px 20px;
color: #000;
}
.main-content {
width: 100%; /* 400px */
height: 100%;
font-family: Roboto;
margin: 0 auto;
background-color: #fff;
padding: 15px 20px 0 20px;
}
.content-top {
background: #f3f2f2;
height: 20px;
margin: 0 auto;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
transform: translate3d(0, 1px, 0);
}
.content-container {
width: 100%;
margin: 0 auto;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
background: #ffffff;
height: 100%;
box-shadow: 0px 0px 18px rgba(0, 0, 0, 0.6);
padding: 25px 0px 0 0px;
overflow: auto;
}
.title-content {
margin: 0px auto;
overflow: auto;
padding: 0 !important;
}
.back-icon {
float: left;
font-size: rem(35);
}
.div-title {
/* padding: 0!important; */
float: left;
margin: 2.5px 0 0 5px;
color: #000 !important;
}
.title {
color: #000 !important;
}
.actions-icon {
float: right;
}
.actions-icon ion-icon {
margin-left: 10px;
float: right;
}
.item-content-date {
color: #797979;
}
.item-content-detail {
color: #000000;
}
.post-item {
width: 100%;
overflow: auto;
margin: 0 auto;
border-radius: 0px;
padding: 0 !important;
}
.post-img {
width: 100%;
height: 100%;
max-height: 400px;
min-height: 350px;
min-width: 350px;
margin: 5px auto;
border-radius: 0px !important;
overflow: hidden;
background-color: white;
display: flex;
justify-content: center;
align-items: center;
background: black;
-webkit-border-radius: 0px !important;
-moz-border-radius: 0px !important;
-ms-border-radius: 0px !important;
-o-border-radius: 0px !important;
}
.post-video {
width: 100%;
height: 100%;
max-height: 400px;
min-height: 350px;
min-width: 350px;
margin: 5px auto;
border-radius: 0px !important;
overflow: hidden;
background-color: white;
display: flex;
justify-content: center;
background: black;
}
video {
max-width: -webkit-fill-available;
}
.post-img img {
height: 100%;
max-height: 420px;
}
.post-content {
margin: 0 auto;
margin-bottom: 35px;
}
.post-title-time {
width: 100%;
overflow: auto;
margin-top: 10px;
}
.post-title {
width: 60%;
float: left;
color: #0d89d1;
}
.post-data {
width: 40%;
float: left;
color: #797979;
text-align: right;
}
.post-description {
color: #000;
}
.font-13-em {
font-size: 0.8125em !important;
}
.numbertext {
color: #f2f2f2;
font-size: 12px;
padding: 8px 12px;
position: absolute;
top: 0;
}
.prev,
.next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
margin-top: -22px;
padding: 16px;
color: white;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
}
/* Position the "next button" to the right */
.next {
right: 0;
border-radius: 3px 0 0 3px;
}
/* On hover, add a black background color with a little bit see-through */
.prev:hover,
.next:hover {
background-color: rgba(0, 0, 0, 0.8);
}
.dot {
cursor: pointer;
height: 15px;
width: 15px;
margin: 0 2px;
background-color: #bbb;
border-radius: 50%;
display: inline-block;
transition: background-color 0.6s ease;
}
.active,
.dot:hover {
background-color: #717171;
}
swiper-container {
width: 100%;
height: 100%;
}
swiper-slide {
text-align: center;
font-size: 18px;
background: #ffff;
display: inline;
justify-content: center;
align-items: center;
}
swiper-slide img {
width: 100%;
height: 100%;
max-height: 400px;
min-height: 350px;
min-width: 350px;
margin: 5px auto;
border-radius: 0px !important;
overflow: hidden;
background-color: white;
display: flex;
justify-content: center;
align-items: center;
background: black;
}
swiper-slide video {
width: 100%;
height: 100%;
max-height: 400px;
min-height: 350px;
min-width: 350px;
margin: 5px auto;
border-radius: 0px !important;
overflow: hidden;
background-color: white;
display: flex;
justify-content: center;
background: black;
}
.swiper-container::part(button-next) {
display: none !important;
.swiper-button-next {
display: none !important;
}
}
.dotsSwiper {
height: 10px;
width: 10px;
background-color: gray;
border-radius: 50%;
display: inline-block;
}
.active-dot {
background-color: black;
}
.dots-container {
width: 100%;
text-align: center;
}
.dots-container span {
display: inline-block; /* Display dots in a row */
margin-right: 5px;
}
+61 -2
View File
@@ -1,4 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
import { checkFileTypeService } from 'src/app/services/checkFileType.service';
import { StopvideoService } from 'src/app/services/stopvideo.service';
@Component({
selector: 'app-swiper',
@@ -7,9 +9,66 @@ import { Component, OnInit } from '@angular/core';
})
export class SwiperPage implements OnInit {
constructor() { }
@Input() publicationList: any;
swiperIndex: number = 0;
@ViewChild('VideoManager') VideoManager;
@ViewChild('videoElement') videoElements: ElementRef | undefined;
@ViewChild('swipers')
swiperRef: ElementRef | undefined;
constructor(
public checkFileType: checkFileTypeService,
public stopvideoService: StopvideoService,
) {
console.log('swieper', this.publicationList)
}
ngOnInit() {
console.log('swieper', this.publicationList)
}
onSlideChange() {
this.swiperIndex = this.swiperRef?.nativeElement.swiper.activeIndex;
console.log(this.swiperIndex)
}
goToSlide(index: number) {
this.swiperIndex = this.swiperRef?.nativeElement.swiper.activeIndex;
this.swiperRef?.nativeElement.swiper.slideTo(index);
console.log('index slide', index)
}
onVisibilityChange = (e: boolean) => {
if (!e) {
this.stopVideo()
}
}
stopVideo() {
var videos = document.querySelectorAll('video');
try {
// Pause each video
videos.forEach(function (video) {
video.pause();
})
const video: HTMLVideoElement = this.videoElements.nativeElement;
video.pause()
/* this.videoElements.forEach(videoElement => {
// You can access the native HTML video element using videoElement.nativeElement
// Do something with each video element
// console.log(video);
}); */
} catch (error) {
console.log(error)
}
}
}
+1 -1
View File
@@ -4,4 +4,4 @@ import { environment as oaprProd } from './suport/oapr'
import { DevDev } from './suport/dev'
export const environment: Environment = DevDev;
export const environment: Environment = oaprProd;